home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998…eptember: Technology Seed / September 98 ADC Seed CD.toast / FireWire 1.1 DR2 SDK / Source / FWIM / LynxFWIM / LynxFWIM.c next >
Encoding:
Text File  |  1998-01-15  |  311.3 KB  |  10,272 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        LynxFWIM.c
  3.  
  4.     Contains:    FireWire interface module software for TI PCI-Lynx 1394 card.
  5.  
  6.     Written by:    Eric W. Anderson
  7.  
  8.     Copyright:    © 1996-1997 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.       <FW76>     5/28/97    EA        Fixed rare case where FWIM jams because an unexpected "special
  13.                                     ack" from Lynx leaves us in limbo.
  14.       <FW75>      4/1/97    EA        Fixed recovery from async receive overflow by turning comparator
  15.                                     back on after DMA is restarted.
  16.       <FW74>     3/18/97    ES        Changed driver description version to final.
  17.       <FW73>     3/10/97    EA        Added support for ReceivePacketOp.  Removed possibly dangerous
  18.                                     debug messages from primary interrupt handlers.
  19.       <FW72>     3/10/97    ES        Changed LynxFWIMUpdateDCLTimeStamp to add one cycle to
  20.                                     compensate for work ahead. Increased maximum number of
  21.                                     simultaneous queued interrupts to 100.
  22.       <FW71>      3/6/97    EA        Changed ISO TX stop mechanism to eliminate aux commands and
  23.                                     double PCLs, to reduce PCI latencies. Stop now uses check on
  24.                                     ready bit before each packet. Also fixed GRF-jam recovery to
  25.                                     actually work.
  26.       <FW70>      3/5/97    EA        Changed to disable CYCMASTER faster (in primary interrupt
  27.                                     handler) if we are no longer root after a bus reset, to reduce
  28.                                     PHY jams. Added recovery mechanism for rare GRF-jam problem.
  29.       <FW69>      3/3/97    ES        Added support for DCLTimeStamp.
  30.       <FW68>     2/27/97    EA        Made changes to try to reduce vulnerability to PHY jams by
  31.                                     eliminating redundant bus resets.
  32.       <FW67>     2/18/97    EA        Changed how we send acks, and how we react to acks. Changed
  33.                                     reset processing of new node ID. Added a bunch of comments about
  34.                                     acks. Also removed LED-blinking code.
  35.       <FW66>     2/14/97    ES        Added LynxFWIMFinalize and LynxFWIMPollInterrupts to plug in
  36.                                     dispatch table.
  37.       <FW65>     2/14/97    ES        Changed to mask out DCL opcode flags.
  38.       <FW64>     2/13/97    EA        Commented out #define LynxFireBug for safety.
  39.       <FW63>     2/12/97    EA        Changed transmit DMA to not hammer Lynx while waiting.
  40.       <FW62>     2/11/97    EA        Added CRC-16 check of serial EEPROM contents.
  41.       <FW61>      2/7/97    EA        Temporary hack to LynxFWIMGetRegisterBaseAddress
  42.       <FW60>      2/6/97    EA        Added routines to load serial EEPROM to find global unique ID
  43.                                     and other HW config info.
  44.       <FW59>      2/6/97    ES        Removed use of status field in FWIMCommandParams record.
  45.       <FW58>      2/4/97    ES        Changed LynxFWIMCreateAsyncTxDonePCLSegment to use logical lynx
  46.                                     fwim data pointer instead of physical pointer when manually
  47.                                     setting asyncTxDoneFlag.
  48.       <FW57>     1/29/97    ES        Fixed implied return warning in LynxFWIMWriteTimer.
  49.       <FW56>     1/29/97    ES        Added check for internal DMA transmit errors to
  50.                                     LynxFWIMAckSecondaryInterruptHandler. Will schedule a transmit
  51.                                     retry 10ms after detecting error.
  52.       <FW55>     1/17/97    EA        Fixed AT DMA hang due to TX disable from bus reset during
  53.                                     transmit
  54.       <FW54>     1/15/97    EA        Fixed Open Firmware/Assigned-address matching bug
  55.       <FW53>      1/9/97    ES        Changed LynxFWIMWriteATF to not explicitly start transmit DMA.
  56.                                     This is done in LynxFWIMAddAsyncTxPCL and was causing DMA
  57.                                     transmit problems.
  58.       <FW52>      1/1/97    ES        Added support for updating DCL commands. Added support for
  59.                                     servicing more than one isoch interrupt at a time.
  60.       <FW51>    12/26/96    ES        Changed to use DCL program stop and release routines.
  61.       <FW50>    12/20/96    ES        Cleaned up LynxFWIMWriteATF.
  62.       <FW49>    12/18/96    ES        Changed GRF overflow handling to not flush GRF.
  63.       <FW48>    12/26/96    ES        Consolidated some parameters in asynch FWIM commands and
  64.                                     processing.
  65.       <FW47>    12/22/96    ES        Changed IsochPortAction to IsochPortControl.
  66.       <FW46>    12/12/96    ES        Took transmit buffer out of FWIMProcessAsynchParams record.
  67.       <FW45>     12/6/96    ES        Changed FWIMInstallParams to FWIMInitializeParams and changed
  68.                                     some of the fields in FWIMInitializeParams. Changed
  69.                                     LynxFWIMInstall to LynxFWIMInitialize. FWIMAsynchCommandParams
  70.                                     were changed to supply the split transaction timeout.
  71.       <FW44>     12/6/96    ES        Changed the process read and lock response packet routines to
  72.                                     return an error if the response code indicates an error.
  73.       <FW43>     12/6/96    ES        Fixed a write to nil bug in LynxFWIMCompileDCLProgram.
  74.       <FW42>    11/26/96    ES        Changed to use FWSetDCLProgramStartProc.
  75.       <FW41>    11/26/96    ES        Changed LynxFWIMWriteATF to wait 100000 times. Changed
  76.                                     LynxFWIMStartAsyncRxPCLProgram to wait for a fixed number of
  77.                                     PCLs to become available before restarting the receive DMA.
  78.       <FW40>    11/11/96    ES        Added LynxFWIMGetUniqueID.
  79.       <FW39>     11/9/96    ES        Changed async receive mechanism. Async receive is disabled once
  80.                                     we've used all the PCLs. PCLs are dynamically added back into
  81.                                     the async receive program as they are freed.
  82.       <FW38>     11/5/96    ES        Changed to use FireWire deferred tasks instead of secondary
  83.                                     interrupts.
  84.       <FW37>     11/5/96    ES        Fixed GRF overflow bug when stopping isoch receiving.
  85.       <FW36>    10/27/96    EA        Fixed my checkin initials (D'oh!)
  86.       <FW35>    10/27/96    EA        Added support for VM everywhere. Also added a lot of comments
  87.       <FW34>    10/18/96    ES        Expanded DCL compiler notification proc. Added call to
  88.                                     FWStartDCLProgram in LynxFWIMStartIsochPort.
  89.       <FW33>     10/4/96    ES        Changed to use FWCallDCLCallProc.
  90.       <FW32>     10/4/96    ES        Replaced DCLSetPacketAttributes with DCLSetTagSyncBits and added
  91.                                     DCLSendPacketWithHeaderStart.
  92.       <FW31>     10/3/96    ES        Changed to use FWIMPluginDispatchTable.
  93.       <FW30>     10/3/96    ES        Got rid of LynxFWIMGetTopologyMap. We now call FWProcessSelfIDs.
  94.                                     Tried to reduce problems with overflowing the ASYNC ring buffer.
  95.       <FW29>     10/2/96    ES        Changed interrupt handling to only queue one secondary interrupt
  96.                                     handler at a time per interrupt source.
  97.       <FW28>     9/25/96    ES        Added asynchronous transaction response FWIM commands. Changed
  98.                                     the way asynchronous requests are processed and responded to.
  99.       <FW27>     9/16/96    ES        Took out some read response and isoch continue stuff.
  100.       <FW26>     9/16/96    ES        Changed FWIM interface to return command acceptance.
  101.       <FW25>     9/16/96    ES        Changed to use response code returned from
  102.                                     FWProcessRead/Write/LockRequest.
  103.       <FW24>     9/11/96    ES        Changed to use speed parameter passed in to asynchronous FWIM
  104.                                     calls and to properly set local speed bits in topology map.
  105.       <FW23>      9/5/96    ES        Changed to call FWProcessRead/Write/LockRequest asynchronously.
  106.       <FW22>      9/3/96    ES        Added interface to send out link on packets.
  107.       <FW21>     8/30/96    ES        Added enable/disable cycle master, set/clear root holdoff bit,
  108.                                     send phy configuration packet, and other stuff to support
  109.                                     isochronous resource management.
  110.       <FW20>     8/29/96    ES        Added capability to set and clear contender bit and to
  111.                                     accurately report state of contender bit in topology map. Also
  112.                                     added support for handling lock requests.
  113.       <FW19>     8/27/96    ES        Fixed a bug in LynxFWIMGetTopologyMap.
  114.       <FW18>     8/26/96    ES        Conditionalize DebugStrs on FWDebugBuild.
  115.       <FW17>     8/26/96    ES        Changed LynxFWIMGetTopologyMap to return local node ID.
  116.       <FW16>     8/19/96    ES        Changed to use separate interrupt pDCLCallProc for each pcl
  117.                                     program. Also changed to clear pDCLCallProc after it's been
  118.                                     handled.
  119.       <FW15>     8/16/96    ES        Implemented hack to treat ack pending as ack complete for
  120.                                     sending write requests to fix mass storage driver.  Also changed
  121.                                     stop isoch port to immediately set channel inactive for receive.
  122.       <FW14>     8/16/96    ES        Changed LynxFWIMReleaseIsochPort to pass status in to
  123.                                     FWIMCommandIsComplete.
  124.       <FW13>     8/15/96    ES        Added compiler notificaton proc for DCL programs. Also added
  125.                                     support for dynamically changing the destination of DCL jumps.
  126.       <FW12>      8/8/96    ES        Improved error handling for allocating isochronous ports. Will
  127.                                     now deallocate isoch port PCLs.
  128.       <FW11>      8/8/96    ES        Changed to use DCL translation services.
  129.       <FW10>      8/7/96    ES        Added option to build driver description for Lynx Lite.
  130.        <FW9>      8/2/96    ES        Updated for more isochronous changes.
  131.        <FW8>      8/1/96    ES        Took out unused local variables.
  132.        <FW7>     7/31/96    ES        Changed to use new isochronous buffer architecture.
  133.        <FW6>     7/11/96    ES        Added dynamic FIFO allocation for isochronous transmission and
  134.                                     changed to handle ITF underflow better.
  135.        <FW5>      7/8/96    ES        Added isoch transmit capability. Still need to work out FIFO
  136.                                     sizing.
  137.        <FW4>      7/2/96    EA        Made all DMA and PCLs cache-aligned, fixed
  138.                                        cycle-master behavior, fixed DMA jam, fixed FIFO
  139.                                     thresholds, etc.
  140.        <FW3>     6/20/96    ES        Changed some comments.
  141.        <FW2>     6/12/96    EA        Fill in contains and written by fields.
  142.        <FW1>     6/12/96    EA        first checked in
  143.  
  144. */
  145.  
  146. // This was adapted from Erik's TIFWIM, long ago.
  147.  
  148. // TIP FOR BEST PERFORMANCE
  149. // Avoid touching Lynx registers.  Lynx may be in the middle of a DMA when you
  150. // do so, and it has to suspend that while it answers your query.  This leads
  151. // to FIFO underflows and overflows.  So touch registers only when there's no
  152. // other choice.  [Note: do as we say, not as we do.]
  153.  
  154. //#define DebugStr(x) strlen(x)
  155.  
  156.  
  157. #include <Types.h>
  158. #include <Errors.h>
  159. #include <Devices.h>
  160. #include <Interrupts.h>
  161. #include <PCI.h>
  162. #include <DriverServices.h>
  163. #include <FireWire.h>
  164. #include <LynxFWIM.h>
  165. /*zzz*/
  166. #include <stdio.h>
  167. char  debugStr[256];
  168. pascal void FWDebugStr(
  169.     ConstStr255Param            debuggerMsg)
  170. {
  171. #ifdef FW_DEBUG_BUILD
  172. #if FW_DEBUG_BUILD
  173.     DebugStr (debuggerMsg);
  174. #endif
  175. #endif
  176. }
  177. /*zzz*/
  178.  
  179. // Define this to check for Logical != Physical (use with VM off)
  180. //#define LynxVMDebug
  181.  
  182. // Define this to enable sending diagnostic messages to FireBug
  183. //#define LynxFireBug
  184.  
  185. #ifdef LynxFireBug
  186. char  fireBug[256];
  187. #endif
  188.  
  189. ////////////////////////////////////////////////////////////////////////////////
  190. //
  191. // Internal procedure prototypes.
  192. //
  193.  
  194. static OSStatus    LynxFWIMInitialize (
  195.     FWIMInitializeParamsPtr        pFWIMInitializeParams);
  196.  
  197. static OSStatus    LynxFWIMFinalize (
  198.     FWIMFinalizeParamsPtr        pFWIMFinalizeParams);
  199.  
  200. static OSStatus    LynxFWIMPollInterrupts (
  201.     FWIMPollInterruptsParamsPtr    pFWIMPollInterruptsParams);
  202.  
  203. static OSStatus    LynxFWIMGetRegisterBaseAddress (
  204.     LynxFWIMDataPtr                pLynxFWIMData);
  205.  
  206. static OSStatus    LynxFWIMInstallInterruptHandler (
  207.     LynxFWIMDataPtr                pLynxFWIMData);
  208.  
  209. static UInt16 LynxFWIMcrc16(
  210.     UInt32                        *data,
  211.     UInt32                        count);
  212.     
  213. static void LynxFWIMControlEEPROM(
  214.     LynxFWIMDataPtr                pLynxFWIMData,
  215.     UInt32                        clock,
  216.     UInt32                        data,
  217.     UInt32                        timer);
  218.  
  219. static UInt32 LynxFWIMWaitForEEPROM(
  220.     LynxFWIMDataPtr                pLynxFWIMData);
  221.     
  222. static void LynxFWIMSendEEPROMBit(
  223.     LynxFWIMDataPtr                pLynxFWIMData,
  224.     UInt32                        bit);
  225.     
  226. static void LynxFWIMSendEEPROMByte(
  227.     LynxFWIMDataPtr                pLynxFWIMData,
  228.     UInt8                        sendByte);
  229.     
  230. static UInt32 LynxFWIMReadEEPROMBit(
  231.     LynxFWIMDataPtr                pLynxFWIMData);
  232.     
  233. static UInt8 LynxFWIMReadEEPROMByte(
  234.     LynxFWIMDataPtr                pLynxFWIMData);
  235.     
  236. static void LynxFWIMStartEEPROM (
  237.     LynxFWIMDataPtr                pLynxFWIMData);
  238.     
  239. static void LynxFWIMStopEEPROM (
  240.     LynxFWIMDataPtr                pLynxFWIMData);
  241.  
  242. static void LynxFWIMProcessEEPROM(
  243.     LynxFWIMDataPtr                pLynxFWIMData);
  244.  
  245. static OSStatus    LynxFWIMFullReset(void);
  246.  
  247. static OSStatus    LynxFWIMExceptionHandler (
  248.     ExceptionInformationPowerPC    *theException);
  249.  
  250. static InterruptMemberNumber    LynxFWIMInterruptHandler (
  251.     InterruptSetMember            interruptSet,
  252.     void                        *interruptRefCon,
  253.     UInt32                        interruptCount);
  254.  
  255. static OSStatus    LynxFWIMDispatchInterrupts (
  256.     LynxFWIMDataPtr                pLynxFWIMData);
  257.  
  258. static void LynxFWIMHandleDMAAsyncPCLInterrupt(
  259.     LynxFWIMDataPtr                pLynxFWIMData);
  260.  
  261. static void LynxFWIMHandleDMAIsochReceivePCLInterrupt(
  262.     LynxFWIMDataPtr                pLynxFWIMData);
  263.  
  264. static void LynxFWIMHandleDMAIsochTransmitPCLInterrupt(
  265.     LynxFWIMDataPtr                pLynxFWIMData);
  266.  
  267. static void    LynxFWIMHandleLinkInterrupt (
  268.     LynxFWIMDataPtr                pLynxFWIMData);
  269.  
  270. static void    LynxFWIMHandleResetInterrupt (
  271.     LynxFWIMDataPtr                pLynxFWIMData);
  272.  
  273. static void    LynxFWIMHandlePhyRegRcvdInterrupt (
  274.     LynxFWIMDataPtr                pLynxFWIMData);
  275.  
  276. static void LynxFWIMHandleMiscInterrupt(
  277.     LynxFWIMDataPtr                pLynxFWIMData);
  278.  
  279. static OSStatus LynxFWIMResetBus (
  280.     FWIMCommandParamsPtr        pFWIMCommandParams,
  281.     UInt32                        *pCommandAcceptance);
  282.  
  283. static OSStatus LynxFWIMSetContenderBit (
  284.     FWIMCommandParamsPtr        pFWIMCommandParams,
  285.     UInt32                        *pCommandAcceptance);
  286.  
  287. static OSStatus LynxFWIMClearContenderBit (
  288.     FWIMCommandParamsPtr        pFWIMCommandParams,
  289.     UInt32                        *pCommandAcceptance);
  290.  
  291. static OSStatus    LynxFWIMEnableCycleMaster (
  292.     FWIMCommandParamsPtr        pFWIMCommandParams,
  293.     UInt32                        *pCommandAcceptance);
  294.  
  295. static OSStatus    LynxFWIMDisableCycleMaster (
  296.     FWIMCommandParamsPtr        pFWIMCommandParams,
  297.     UInt32                        *pCommandAcceptance);
  298.  
  299. static OSStatus    LynxFWIMSetRootHoldoffBit (
  300.     FWIMCommandParamsPtr        pFWIMCommandParams,
  301.     UInt32                        *pCommandAcceptance);
  302.  
  303. static OSStatus    LynxFWIMClearRootHoldoffBit (
  304.     FWIMCommandParamsPtr        pFWIMCommandParams,
  305.     UInt32                        *pCommandAcceptance);
  306.  
  307. static OSStatus    LynxFWIMGetUniqueID (
  308.     FWIMGetUniqueIDParamsPtr    pFWIMGetUniqueIDParams,
  309.     UInt32                        *pCommandAcceptance);
  310.  
  311. static OSStatus    LynxFWIMSendLinkOnPacket (
  312.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  313.     UInt32                        *pCommandAcceptance);
  314.  
  315. static OSStatus    LynxFWIMSendPhyConfigurationPacket (
  316.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  317.     UInt32                        *pCommandAcceptance);
  318.  
  319. static void    LynxFWIMWritePhyRegister (
  320.     LynxRegistersPtr            pLinkRegs,
  321.     UInt8                        regAddress,
  322.     UInt8                        regData);
  323.  
  324. static UInt8    LynxFWIMReadPhyRegister (
  325.     LynxRegistersPtr            pLinkRegs,
  326.     UInt8                        regAddress);
  327.  
  328. static void LynxFWIMPrepareAsyncDMA(
  329.     LynxFWIMDataPtr                pLynxFWIMData,
  330.     UInt32                        channel);
  331.  
  332. static void LynxFWIMAddAsyncRxPCL (
  333.     LynxPCLPtr                    pPCL);
  334.  
  335. static void LynxFWIMCreateAsyncRxPCLProgram (
  336.     LynxFWIMDataPtr                pLynxFWIMData);
  337.  
  338. static void LynxFWIMCreateAsyncRxDummyPCL (
  339.     LynxFWIMDataPtr                pLynxFWIMData);
  340.  
  341. static void LynxFWIMCreateAsyncRxOverflowPCLSegment (
  342.     LynxFWIMDataPtr                pLynxFWIMData);
  343.  
  344. static void LynxFWIMStartAsyncRxPCLProgram (
  345.     LynxFWIMDataPtr                pLynxFWIMData,
  346.     LynxPCLPtr                    pStartPCL);
  347.  
  348. static void LynxFWIMAddAsyncTxPCL (
  349.     LynxPCLPtr                    pPCL);
  350.  
  351. static void LynxFWIMCreateAsyncTxDummyPCL (
  352.     LynxFWIMDataPtr                pLynxFWIMData);
  353.  
  354. static void LynxFWIMCreateAsyncTxDonePCLSegment (
  355.     LynxFWIMDataPtr                pLynxFWIMData);
  356.  
  357. static void LynxFWIMCreateAsyncTxDataPCL (
  358.     LynxFWIMDataPtr                pLynxFWIMData);
  359.  
  360. static void LynxFWIMStartAsyncTxPCLProgram (
  361.     LynxFWIMDataPtr                pLynxFWIMData,
  362.     LynxPCLPtr                    pStartPCL);
  363.  
  364. static void LynxFWIMSetLinkControl (
  365.     LynxFWIMDataPtr                pLynxFWIMData,
  366.     UInt32                        linkControl);
  367.  
  368. static void LynxFWIMSetAsyncRxComparatorMask1 (
  369.     LynxFWIMDataPtr                pLynxFWIMData,
  370.     UInt32                        mask1);
  371.  
  372. static OSStatus LynxFWIMWriteATF(
  373.     LynxFWIMDataPtr                pLynxFWIMData,
  374.     UInt32                        transmitType,
  375.     UInt32                        speed,
  376.     UInt32                        baseCount,
  377.     UInt32                        data1,
  378.     UInt32                        data2,
  379.     UInt32                        data3,
  380.     UInt32                        data4,
  381.     UInt32                        extCount,
  382.     UInt32                        *extData);
  383.  
  384. static OSStatus    LynxFWIMBuildAsyncTxPCL (
  385.     LynxFWIMDataPtr                pLynxFWIMData,
  386.     LynxPCLPtr                    pPCL,
  387.     IOPreparationID                *pIOPreparationID,
  388.     UInt32                        pclControl,
  389.     Ptr                            buffer1,
  390.     UInt32                        size1,
  391.     Ptr                            buffer2,
  392.     UInt32                        size2);
  393.  
  394. static OSStatus    LynxFWIMRead (
  395.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  396.     UInt32                        *pCommandAcceptance);
  397.  
  398. static OSStatus    LynxFWIMReadResponse (
  399.     FWIMAsynchResponseCommandParamsPtr
  400.                                 pFWIMAsynchResponseCommandParams,
  401.     UInt32                        *pCommandAcceptance);
  402.  
  403. static OSStatus    LynxFWIMWriteTimer (
  404.     void                        *p1,
  405.     void                        *p2);
  406.  
  407. static OSStatus    LynxFWIMWrite (
  408.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  409.     UInt32                        *pCommandAcceptance);
  410.  
  411. static OSStatus    LynxFWIMWriteResponse (
  412.     FWIMAsynchResponseCommandParamsPtr
  413.                                 pFWIMAsynchResponseCommandParams,
  414.     UInt32                        *pCommandAcceptance);
  415.  
  416. static OSStatus    LynxFWIMLock (
  417.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  418.     UInt32                        *pCommandAcceptance);
  419.  
  420. static OSStatus    LynxFWIMLockResponse (
  421.     FWIMAsynchResponseCommandParamsPtr
  422.                                 pFWIMAsynchResponseCommandParams,
  423.     UInt32                        *pCommandAcceptance);
  424.  
  425. static Boolean    LynxFWIMIsCompilableDCLProgram (
  426.     DCLProgramID                dclProgramID);
  427.  
  428. static OSStatus LynxFWIMCompileDCLProgram (
  429.     LynxFWIMDataPtr                pLynxFWIMData,
  430.     DCLProgramID                dclProgramID,
  431.     UInt32                        pclChannelNum,
  432.     UInt32                        channelNum,
  433.     UInt32                        speed);
  434.  
  435. static OSStatus LynxFWIMAddDCL (
  436.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  437.     DCLCommandPtr                pDCLCommand);
  438.  
  439. static OSStatus LynxFWIMAddReceivePacketStartDCL (
  440.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  441.     DCLCommandPtr                pDCLCommand);
  442.  
  443. static OSStatus LynxFWIMAddReceivePacketDCL (
  444.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  445.     DCLCommandPtr                pDCLCommand);
  446.  
  447. static OSStatus LynxFWIMAddSendPacketStartDCL (
  448.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  449.     DCLCommandPtr                pDCLCommand);
  450.  
  451. static OSStatus LynxFWIMAddSendPacketWithHeaderStartDCL (
  452.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  453.     DCLCommandPtr                pDCLCommand);
  454.  
  455. static OSStatus LynxFWIMAddSendPacketDCL (
  456.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  457.     DCLCommandPtr                pDCLCommand);
  458.  
  459. static OSStatus LynxFWIMAddCallProcDCL (
  460.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  461.     DCLCommandPtr                pDCLCommand);
  462.  
  463. static OSStatus LynxFWIMAddJumpDCL (
  464.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  465.     DCLCommandPtr                pDCLCommand);
  466.  
  467. static OSStatus LynxFWIMUpdateDCLListDCL (
  468.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  469.     DCLCommandPtr                pDCLCommand);
  470.  
  471. static OSStatus LynxFWIMTimeStampDCL (
  472.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  473.     DCLCommandPtr                pDCLCommand);
  474.  
  475. static OSStatus    LynxFWIMPCLStart (
  476.     LynxFWIMDataPtr                pLynxFWIMData,
  477.     LynxPCLBuildStatePtr        *ppLynxPCLBuildState,
  478.     LynxPCLPtr                    *ppPCL);
  479.  
  480. static OSStatus LynxFWIMAddLabelDCL(
  481.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  482.     DCLCommandPtr                pDCLCommand);
  483.  
  484. static OSStatus LynxFWIMAddSetTagSyncBitsDCL (
  485.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  486.     DCLCommandPtr                pDCLCommand);
  487.  
  488. static OSStatus    LynxFWIMPCLAllocateWord (
  489.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  490.     UInt32                        **ppWord);
  491.  
  492. static OSStatus    LynxFWIMPCLNew (
  493.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  494.     LynxPCLPtr                    *ppPCL,
  495.     UInt32                        refCon);
  496.  
  497. static OSStatus    LynxFWIMPCLNewIsochReceive (
  498.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  499.     LynxPCLPtr                    *ppPCL,
  500.     UInt32                        refCon,
  501.     UInt32                        speed);
  502.  
  503. static OSStatus    LynxFWIMPCLNewIsochTransmit (
  504.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  505.     LynxPCLPtr                    *ppPCL,
  506.     UInt32                        refCon,
  507.     UInt32                        speed);
  508.  
  509. static OSStatus    LynxFWIMPCLExtend (
  510.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  511.     UInt32                        pclType);
  512.  
  513. static OSStatus    LynxFWIMPCLLoadTemp (
  514.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  515.     Ptr                            pSource);
  516.  
  517. static OSStatus    LynxFWIMPCLStoreTemp (
  518.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  519.     Ptr                            pDest);
  520.  
  521. static OSStatus    LynxFWIMPCLStore0 (
  522.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  523.     Ptr                            pDest);
  524.  
  525. static OSStatus    LynxFWIMPCLStore1 (
  526.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  527.     Ptr                            pDest);
  528.  
  529. static OSStatus    LynxFWIMPCLCompareTemp16WithMask (
  530.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  531.     UInt16                        compareValue,
  532.     UInt16                        compareMask);
  533.  
  534. static OSStatus    LynxFWIMPCLBranchIfEqual (
  535.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  536.     DCLLabelPtr                    pDCLLabel);
  537.  
  538. static OSStatus    LynxFWIMPCLJump (
  539.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  540.     DCLLabelPtr                    pDCLLabel,
  541.     Ptr                            *ppPCLCommand);
  542.  
  543. static OSStatus    LynxFWIMPCLInterrupt (
  544.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  545.     DCLCommandPtr                pDCLCommand,
  546.     Ptr                            *ppPCLCommand);
  547.  
  548. static OSStatus    LynxFWIMPCLAuxCommand (
  549.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  550.     UInt32                        auxCommand,
  551.     UInt32                        waitBranchCondition,
  552.     UInt32                        auxParam);
  553.  
  554. static OSStatus    LynxFWIMPCLAddTransferBuffer (
  555.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  556.     Ptr                            buffer,
  557.     UInt32                        bufferSize,
  558.     Ptr                            *ppPCLCommand,
  559.     UInt32                        bufferAddrType);
  560.  
  561. static OSStatus    LynxFWIMResolveDCLLabel (
  562.     DCLLabelPtr                    pDCLLabel);
  563.  
  564. static LynxPCLPtr    LynxFWIMGetDCLLabelPCLPtr (
  565.     DCLLabelPtr                    pDCLLabel);
  566.  
  567. static OSStatus    LynxFWIMPCLLabel (
  568.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  569.     DCLLabelPtr                    pDCLLabel);
  570.  
  571. static LynxPCLPtr    LynxFWIMGetPCLFromDCL (
  572.     DCLCommandPtr                pDCLCommand);
  573.  
  574. static OSStatus        LynxFWIMDCLCompilerNotification (
  575.     DCLProgramID                dclProgramID,
  576.     UInt32                        notificationType,
  577.     DCLCommandPtr                *dclCommandList,
  578.     UInt32                        numDCLCommands);
  579.  
  580. static OSStatus        LynxFWIMDCLCompilerUpdateNotification (
  581.     DCLProgramID                dclProgramID,
  582.     DCLCommandPtr                *dclCommandList,
  583.     UInt32                        numDCLCommands);
  584.  
  585. static OSStatus        LynxFWIMUpdateDCLTimeStamp (
  586.     DCLCommandPtr                pDCLCommand);
  587.  
  588. static OSStatus        LynxFWIMDCLCompilerModifyNotification (
  589.     DCLProgramID                dclProgramID,
  590.     DCLCommandPtr                *dclCommandList,
  591.     UInt32                        numDCLCommands);
  592.  
  593. static OSStatus    LynxFWIMAllocatePCLBuildState (
  594.     LynxFWIMDataPtr                pLynxFWIMData,
  595.     LynxPCLBuildStatePtr        *ppLynxPCLBuildState);
  596.  
  597. static OSStatus    LynxFWIMAllocatePCL (
  598.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  599.     LynxPCLPtr                    *ppPCL);
  600.  
  601. static void LynxFWIMDeallocatePCLPools (
  602.     LynxPCLPoolDataPtr            pLynxPCLPoolDataList);
  603.  
  604. static void    LynxFWIMRunDCLProgram (
  605.     LynxIsochPortDataPtr        pLynxIsochPortData,
  606.     Ptr                            packetBuffer,
  607.     UInt32                        packetSize,
  608.     DCLCommandPtr                *ppDCLCommand);
  609.  
  610. static void    LynxFWIMDCLReceivePacketStart (
  611.     Ptr                            *pPacketBuffer,
  612.     UInt32                        *pPacketSize,
  613.     DCLCommandPtr                *ppDCLCommand,
  614.     Boolean                        *pWaitForPacket);
  615.  
  616. static void    LynxFWIMDCLReceiveBuffer (
  617.     Ptr                            *pPacketBuffer,
  618.     UInt32                        *pPacketSize,
  619.     DCLCommandPtr                *ppDCLCommand,
  620.     Boolean                        *pWaitForPacket);
  621.  
  622. static OSStatus LynxFWIMAllocateIsochPort (
  623.     FWIMAllocateIsochPortParamsPtr
  624.                                 pFWIMAllocateIsochPortParams,
  625.     UInt32                        *pCommandAcceptance);
  626.  
  627. static OSStatus LynxFWIMReleaseIsochPort (
  628.     FWIMReleaseIsochPortParamsPtr
  629.                                 pFWIMReleaseIsochPortParams,
  630.     UInt32                        *pCommandAcceptance);
  631.  
  632. static OSStatus _LynxFWIMReleaseIsochPort (
  633.     LynxFWIMDataPtr                pLynxFWIMData,
  634.     LynxIsochPortDataPtr        pLynxIsochPortData);
  635.  
  636. static OSStatus LynxFWIMStartIsochPort (
  637.     FWIMIsochPortControlParamsPtr
  638.                                 pFWIMIsochPortControlParams,
  639.     UInt32                        *pCommandAcceptance);
  640.  
  641. static OSStatus LynxFWIMStopIsochPort (
  642.     FWIMIsochPortControlParamsPtr
  643.                                 pFWIMIsochPortControlParams,
  644.     UInt32                        *pCommandAcceptance);
  645.  
  646. static OSStatus LynxFWIMStartTalkingDCLProgram (
  647.     DCLProgramID                dclProgramID);
  648.  
  649. static OSStatus LynxFWIMStartListeningDCLProgram (
  650.     DCLProgramID                dclProgramID);
  651.  
  652. static OSStatus LynxFWIMStopTalkingDCLProgram (
  653.     DCLProgramID                dclProgramID);
  654.  
  655. static OSStatus LynxFWIMStopListeningDCLProgram (
  656.     DCLProgramID                dclProgramID);
  657.  
  658. static OSStatus LynxFWIMReleaseDCLProgram (
  659.     DCLProgramID                dclProgramID);
  660.  
  661. static OSStatus    LynxFWIMReadRequestTimeoutHandler (
  662.     void                        *p1,
  663.     void                        *p2);
  664.  
  665. static OSStatus    LynxFWIMWriteRequestTimeoutHandler (
  666.     void                        *p1,
  667.     void                        *p2);
  668.  
  669. static OSStatus    LynxFWIMLockRequestTimeoutHandler (
  670.     void                        *p1,
  671.     void                        *p2);
  672.  
  673. static void    LynxFWIMDMAAsyncPCLDeferredTask(
  674.     void                        *p1,
  675.     void                        *p2);
  676.     
  677. static void    LynxFWIMDMAIsochReceivePCLDeferredTask(
  678.     void                        *p1,
  679.     void                        *p2);
  680.     
  681. static void    LynxFWIMDMAIsochTransmitDeferredTask(
  682.     void                        *p1,
  683.     void                        *p2);
  684.     
  685. static void    LynxFWIMResetDeferredTask (
  686.     void                        *p1,
  687.     void                        *p2);
  688.  
  689. static OSStatus    LynxFWIMDelayedReset(
  690.     void                        *p1,
  691.     void                        *p2);
  692.  
  693. static void    LynxFWIMMiscInterruptDeferredTask (
  694.     void                        *p1,
  695.     void                        *p2);
  696.  
  697. static OSStatus    LynxFWIMAckSecondaryInterruptHandler (
  698.     void                        *p1,
  699.     void                        *p2);
  700.  
  701. static void LynxFWIMProcessPacket (
  702.     LynxFWIMDataPtr                pLynxFWIMData,
  703.     LynxPCLPtr                    pPCL,
  704.     Ptr                            packetBuffer,
  705.     UInt32                        packetSize);
  706.  
  707. static void    LynxFWIMProcessSelfIDPacket (
  708.     LynxFWIMDataPtr                pLynxFWIMData,
  709.     LynxPCLPtr                    pPCL,
  710.     Ptr                            packetBuffer,
  711.     UInt32                        packetSize);
  712.  
  713. static void    LynxFWIMProcessWriteQuadletPacket (
  714.     LynxFWIMDataPtr                pLynxFWIMData,
  715.     LynxPCLPtr                    pPCL,
  716.     Ptr                            packetBuffer,
  717.     UInt32                        packetSize);
  718.  
  719. static void    LynxFWIMProcessWriteQuadletRequestCompletionProc (
  720.     FWIMProcessParamsPtr        pFWIMProcessParams);
  721.  
  722. static void    LynxFWIMProcessWriteBlockPacket (
  723.     LynxFWIMDataPtr                pLynxFWIMData,
  724.     LynxPCLPtr                    pPCL,
  725.     Ptr                            packetBuffer,
  726.     UInt32                        packetSize);
  727.  
  728. static void    LynxFWIMProcessWriteBlockRequestCompletionProc (
  729.     FWIMProcessParamsPtr        pFWIMProcessParams);
  730.  
  731. static void    LynxFWIMProcessWriteResponsePacket (
  732.     LynxFWIMDataPtr                pLynxFWIMData,
  733.     LynxPCLPtr                    pPCL,
  734.     Ptr                            packetBuffer,
  735.     UInt32                        packetSize);
  736.  
  737. static void    LynxFWIMProcessReadQuadletPacket (
  738.     LynxFWIMDataPtr                pLynxFWIMData,
  739.     LynxPCLPtr                    pPCL,
  740.     Ptr                            packetBuffer,
  741.     UInt32                        packetSize);
  742.  
  743. static void    LynxFWIMProcessReadQuadletRequestCompletionProc (
  744.     FWIMProcessParamsPtr        pFWIMProcessParams);
  745.  
  746. static void    LynxFWIMProcessReadBlockPacket (
  747.     LynxFWIMDataPtr                pLynxFWIMData,
  748.     LynxPCLPtr                    pPCL,
  749.     Ptr                            packetBuffer,
  750.     UInt32                        packetSize);
  751.  
  752. static void    LynxFWIMProcessReadBlockRequestCompletionProc (
  753.     FWIMProcessParamsPtr        pFWIMProcessParams);
  754.  
  755. static void    LynxFWIMProcessReadQuadletResponsePacket (
  756.     LynxFWIMDataPtr                pLynxFWIMData,
  757.     LynxPCLPtr                    pPCL,
  758.     Ptr                            packetBuffer,
  759.     UInt32                        packetSize);
  760.  
  761. static void    LynxFWIMProcessReadBlockResponsePacket (
  762.     LynxFWIMDataPtr                pLynxFWIMData,
  763.     LynxPCLPtr                    pPCL,
  764.     Ptr                            packetBuffer,
  765.     UInt32                        packetSize);
  766.  
  767. static void    LynxFWIMProcessLockPacket (
  768.     LynxFWIMDataPtr                pLynxFWIMData,
  769.     LynxPCLPtr                    pPCL,
  770.     Ptr                            packetBuffer,
  771.     UInt32                        packetSize);
  772.  
  773. static void    LynxFWIMProcessLockRequestCompletionProc (
  774.     FWIMProcessParamsPtr        pFWIMProcessParams);
  775.  
  776. static void    LynxFWIMProcessIsochronousBlockPacket (
  777.     LynxFWIMDataPtr                pLynxFWIMData,
  778.     LynxPCLPtr                    pPCL,
  779.     Ptr                            packetBuffer,
  780.     UInt32                        packetSize);
  781.  
  782. static void    LynxFWIMProcessLockResponsePacket (
  783.     LynxFWIMDataPtr                pLynxFWIMData,
  784.     LynxPCLPtr                    pPCL,
  785.     Ptr                            packetBuffer,
  786.     UInt32                        packetSize);
  787.  
  788. static void    LynxFWIMSetupFIFOs (
  789.     LynxFWIMDataPtr                pLynxFWIMData);
  790.     
  791. #ifdef LynxFireBug
  792. static void LynxFWIMFireBugMsg (
  793.     LynxFWIMDataPtr                pLynxFWIMData,
  794.     char                         *msg);
  795. #endif
  796.  
  797.  
  798. ////////////////////////////////////////////////////////////////////////////////
  799. //
  800. // The driver descriptor.
  801. //
  802.  
  803. DriverDescription                TheDriverDescription =
  804. {
  805.     kTheDescriptionSignature,
  806.     kInitialDriverDescriptor,
  807.     {
  808. #ifndef LynxLiteFWIM
  809.         "\ppci403,605",
  810. #else
  811.         "\ppci104c,8003",
  812. #endif
  813.         1, 0, finalStage, 1,
  814.     },
  815.     {
  816.         kDriverIsUnderExpertControl,
  817.         "\pLynxFWIM",
  818.     },
  819.  
  820.     1,
  821.     kServiceCategoryFWIM,
  822.     0,
  823.     1,0,0,0
  824. };
  825.  
  826.  
  827. ////////////////////////////////////////////////////////////////////////////////
  828. //
  829. // The plug in dispatch table.
  830. //
  831.  
  832. FWIMPluginDispatchTable            ThePluginDispatchTable =
  833. {
  834.     kFWIMPluginVersion,
  835.     LynxFWIMInitialize,
  836.     LynxFWIMFinalize,
  837.     LynxFWIMPollInterrupts,
  838.     LynxFWIMSendLinkOnPacket,
  839.     LynxFWIMSendPhyConfigurationPacket,
  840.     LynxFWIMRead,
  841.     LynxFWIMReadResponse,
  842.     LynxFWIMWrite,
  843.     LynxFWIMWriteResponse,
  844.     LynxFWIMLock,
  845.     LynxFWIMLockResponse,
  846.     LynxFWIMAllocateIsochPort,
  847.     LynxFWIMReleaseIsochPort,
  848.     LynxFWIMStartIsochPort,
  849.     LynxFWIMStopIsochPort,
  850.     LynxFWIMResetBus,
  851.     LynxFWIMSetContenderBit,
  852.     LynxFWIMClearContenderBit,
  853.     LynxFWIMEnableCycleMaster,
  854.     LynxFWIMDisableCycleMaster,
  855.     LynxFWIMSetRootHoldoffBit,
  856.     LynxFWIMClearRootHoldoffBit,
  857.     LynxFWIMGetUniqueID
  858. };
  859.  
  860.  
  861. ////////////////////////////////////////////////////////////////////////////////
  862. //
  863. // LynxFWIMInitialize
  864. //
  865. //   This is the FWIM installer proc.  It allocates the FWIM data record, gets
  866. // the register base address, installs the interrupt handler, enables the
  867. // register memory space, sets the chip up to receive selfID packets,
  868. // enables bus reset interrupts, and initiates a bus reset to get the topology
  869. // map.
  870. //zzz Clean up on error???
  871. //zzz Do we always need to initiate a bus reset???
  872. //
  873.  
  874. // Ugly - right now, LynxFWIMFullReset is called from some places where this value isn't available
  875. static LynxFWIMDataPtr HACKdata;
  876. static UInt32 NoPhyReset = 0;
  877.  
  878. static OSStatus    LynxFWIMInitialize(
  879.     FWIMInitializeParamsPtr        pFWIMInitializeParams)
  880. {
  881.     LynxFWIMDataPtr                pLynxFWIMData;
  882.     RegEntryIDPtr                pFWIMRegEntryID;
  883.     Ptr                            p;
  884.     IOPreparationTable            *ioPrep;
  885.     UInt32                        pageSize, totalAlloc;
  886.     UInt32                        bufsPerPage, bufPages;
  887.     UInt32                        pclsPerPage, pclPages;
  888.     UInt32                        doBuf, doPage, bufsDone, offset;
  889.     Ptr                            logPage, physPage;
  890.     OSStatus                    status = noErr;
  891.  
  892.     FWDebugStr ((ConstStr255Param) "\pLynxFWIMInitialize");
  893.  
  894.     pageSize = GetLogicalPageSize ();
  895.     
  896.     // Allocate Lynx FWIM data.
  897.     // Parts of this struct will be phyiscally addressed, so we need
  898.     // to make sure those parts don't straddle a page boundary.  To
  899.     // guarantee this, we put them first in the struct, and we'll
  900.     // page-align the whole struct, and map the first page.
  901.     
  902.     p = PoolAllocateResident (sizeof (LynxFWIMData) + pageSize, true);
  903.     if (p)
  904.     {
  905.         p = (Ptr) (((UInt32) p + (pageSize - 1)) & ~(pageSize - 1));    // page-align
  906.         pLynxFWIMData = (LynxFWIMDataPtr) p;
  907.         
  908.         pLynxFWIMData->pageSize = pageSize;
  909.         pLynxFWIMData->pageShift = 1;
  910.         while (pageSize >>= 1)
  911.             pLynxFWIMData->pageShift++;
  912.         pageSize = pLynxFWIMData->pageSize;
  913.         
  914.         ioPrep = &pLynxFWIMData->fwimDataIOPrep;
  915.         ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
  916.         ioPrep->addressSpace = kCurrentAddressSpaceID;            // default
  917.         ioPrep->granularity = 0;                                // do it all now
  918.         ioPrep->firstPrepared = 0;
  919.         ioPrep->mappingEntryCount = 1;                            // # of pages we will use
  920.         ioPrep->logicalMapping = 0;
  921.         ioPrep->physicalMapping = &pLynxFWIMData->fwimDataPhys;    // return phys addr
  922.         ioPrep->rangeInfo.range.base = (void *) pLynxFWIMData;    // first addr to map
  923.         ioPrep->rangeInfo.range.length = pageSize;                // map one page
  924.         
  925.         // there is no CheckpointIO which matches this.  It will be held down forever.
  926.         status = PrepareMemoryForIO (ioPrep);
  927.         if (status != noErr)
  928.         {
  929.             sprintf (debugStr, "FWIMData PrepMemIO status %ld    logical %08lx physical %08lx len %lx",
  930.                      (long) status,
  931.                      (long) ioPrep->rangeInfo.range.base,
  932.                      (long) pLynxFWIMData->fwimDataPhys,
  933.                      (long) ioPrep->rangeInfo.range.length);
  934.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  935.         }
  936.         
  937.         if (status == noErr)
  938.         {
  939.             pFWIMInitializeParams->fwimSpecificData = (UInt32) pLynxFWIMData;
  940.         }
  941.         
  942.     }
  943.     else
  944.     {
  945.         status = memFullErr;
  946.     }
  947.  
  948. // for FullReset, below
  949.     HACKdata = pLynxFWIMData;
  950.  
  951.     // Get notification proc and name registry ID.
  952.     if (status == noErr)
  953.     {
  954.         pLynxFWIMData->fwimID = pFWIMInitializeParams->fwimID;
  955.         pLynxFWIMData->FWIMRegEntryID = pFWIMInitializeParams->fwimRegEntryID;
  956.         pFWIMRegEntryID = &(pLynxFWIMData->FWIMRegEntryID);
  957.     }
  958.  
  959.     // Get register base address.
  960.     if (status == noErr)
  961.     {
  962.         status = LynxFWIMGetRegisterBaseAddress (pLynxFWIMData);
  963.     }
  964.  
  965.     // Note - sometimes these buffers are used to assemble response packets
  966.     // So even if only a few quads are used in receiving, the rest of the buffer
  967.     // may still be written to later (see LynxFWIMProcessReadBlockPacket, etc.)
  968.     
  969.     // Allocate async / self-ID buffers:
  970.     // Buffers will not span page boundaries (for now, max rcv packet fits in a page)
  971.     // and will be 32-byte aligned for best Lynx performance.  To save memory, alloc
  972.     // one big buffer, prep it for I/O, and carve it up.  If marked for input, we can
  973.     // re-use it over and over with no VM upkeep.  kPacketBufferSize must be multiple of 32.
  974.     // PCLs are PCL-size-aligned, PCL-size is 128 and must divide the page size (easy).
  975.     
  976.     // Use a single allocation for async xmit/rcv buffers and xmit/rcv PCLs.  Marking
  977.     // all the memory as "input | output" may prevent some optimizations - future feature.
  978.     
  979.     // Note, because we don't span page boundaries, we don't need to request contig
  980.     // memory.  Change to ordinary allocate once it's working.  (Async rcv PCLs do span
  981.     // pages, fix that first)
  982.     
  983.     if (status == noErr)
  984.     {
  985.         bufsPerPage = pageSize / kPacketBufferSize;
  986.         bufPages = (kAsyncBufs + bufsPerPage - 1) / bufsPerPage;
  987.         pclsPerPage = pageSize / sizeof (LynxPCL);
  988.         pclPages = (kAsyncBufs + pclsPerPage - 1) / pclsPerPage;
  989.         
  990.         totalAlloc = bufPages;                                // Space for async rcv bufs
  991.         totalAlloc += 1;                                    // Space for async xmit buf
  992.         totalAlloc += pclPages;                                // Space for async rcv PCLs
  993.         totalAlloc += 1;                                    // Space for async xmit PCLs
  994.         totalAlloc += 1;                                    // Round up to page boundary
  995.         
  996.         // Use PoolAllocate to get a page table - don't use the stack.
  997.         
  998.         p = MemAllocatePhysicallyContiguous (totalAlloc * pageSize, false);
  999.         
  1000.         if (!p)
  1001.         {
  1002.             status = memFullErr;
  1003.             sprintf (debugStr, "Async buf/PCL alloc failure, asked for %ld",
  1004.                      (long) totalAlloc * pageSize);
  1005.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1006.         }
  1007.         
  1008.         if (status == noErr)
  1009.         {
  1010.             // I think MemAllocatePhysicallyContiguous gives us memory starting
  1011.             // on a page boundary.  But just in case, align ourselves:
  1012.             
  1013.             sprintf (debugStr, "Allocated phys memory at %08lx", (long) p);
  1014.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1015.  
  1016.             p = (Ptr) ((((UInt32) p) + (pageSize - 1)) & ~(pageSize - 1));        // page-align
  1017.  
  1018.             sprintf (debugStr, "              Aligned to %08lx", (long) p);
  1019.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1020.  
  1021.             // Mark this memory for Input, and learn the physical address    
  1022.             ioPrep = &pLynxFWIMData->ioPrep;
  1023.             ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
  1024.             ioPrep->addressSpace = kCurrentAddressSpaceID;        // default
  1025.             ioPrep->granularity = 0;                            // do it all now
  1026.             ioPrep->firstPrepared = 0;
  1027.             ioPrep->mappingEntryCount = totalAlloc;                // # of pages we will use
  1028.             ioPrep->logicalMapping = 0;
  1029.             ioPrep->physicalMapping = pLynxFWIMData->physAddrs;    // return list of phys addrs
  1030.             ioPrep->rangeInfo.range.base = (void *) p;
  1031.             ioPrep->rangeInfo.range.length = totalAlloc * pageSize;
  1032.             
  1033.             // There is no CheckpointIO which matches this.  The buffers are ours for keeps.
  1034.             status = PrepareMemoryForIO (ioPrep);
  1035.             if (status != noErr)
  1036.             {
  1037.                 sprintf (debugStr, "PrepMemIO status %ld    logical %08lx physical %08lx len %lx",
  1038.                          (long) status,
  1039.                          (long) ioPrep->rangeInfo.range.base,
  1040.                          (long) pLynxFWIMData->physAddrs[0],
  1041.                          (long) ioPrep->rangeInfo.range.length);
  1042.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1043.             }
  1044.         }
  1045.  
  1046.         // Carve up what we got and store away the addrs
  1047.         if (status == noErr)
  1048.         {
  1049.             // Async rcv buffers (kAsykcBufs)
  1050.             
  1051.             bufsDone = 0;
  1052.             for (doBuf = 0; doBuf < bufPages; doBuf++)
  1053.             {
  1054.                 logPage = p + (doBuf * pageSize);
  1055.                 physPage = (Ptr) pLynxFWIMData->physAddrs[doBuf];
  1056.                 
  1057.                 for (doPage = 0; doPage < bufsPerPage; doPage++)
  1058.                 {
  1059.                     if (bufsDone < kAsyncBufs)
  1060.                     {
  1061.                         offset = doPage * kPacketBufferSize;
  1062.                         pLynxFWIMData->asyncBuf[bufsDone] = logPage + offset;
  1063.                         pLynxFWIMData->asyncBufPhys[bufsDone] = physPage + offset;
  1064.                     
  1065.                         bufsDone++;
  1066.                     }
  1067.                 }
  1068.             }
  1069.             sprintf (debugStr, "Async bufs ready, log base %08lx, phys base %08lx, count %lx",
  1070.                      (long) pLynxFWIMData->asyncBuf,
  1071.                      (long) pLynxFWIMData->asyncBufPhys,
  1072.                      (long) kAsyncBufs);
  1073.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1074.             
  1075.             // Async xmit buffer (1)
  1076.             
  1077.             p += (bufPages * pageSize);
  1078.             pLynxFWIMData->asyncXmitBuf = p;
  1079.             pLynxFWIMData->asyncXmitBufPhys = pLynxFWIMData->physAddrs[bufPages];
  1080.             
  1081.             // Async rcv PCLs (kAsykcBufs)
  1082.             // WARNING rcv code assumes all PCLs are contiguous.
  1083.             // If made non-contig, will have to change several places
  1084.             
  1085.             p += pageSize;
  1086.             pLynxFWIMData->asyncPCL = (LynxPCL *) p;
  1087.             pLynxFWIMData->asyncPCLPhys = pLynxFWIMData->physAddrs[bufPages + 1];
  1088.             
  1089.             // Async xmit PCLs (3)
  1090.  
  1091.             p += (pclPages * pageSize);
  1092.             pLynxFWIMData->asyncXmitPCL = (LynxPCL *) p;
  1093.             pLynxFWIMData->asyncXmitPCLPhys = pLynxFWIMData->physAddrs[bufPages + 1 + pclPages];
  1094.         }
  1095.     }
  1096.  
  1097.     // Allocate async receive PCL data records.
  1098.     if (status == noErr)
  1099.     {
  1100.         p = PoolAllocateResident (sizeof (LynxAsyncRxPCLData) * kAsyncBufs, true);
  1101.         
  1102.         if (p)
  1103.             pLynxFWIMData->lynxAsyncRxPCLDataList = (LynxAsyncRxPCLDataPtr) p;
  1104.         else
  1105.             status = memFullErr;
  1106.     }
  1107.  
  1108.     // Allocate async transmit PCL data records.
  1109.     if (status == noErr)
  1110.     {
  1111.         p = PoolAllocateResident (sizeof (LynxAsyncTxPCLData) * kNumAsyncTxPCLs, true);
  1112.         
  1113.         if (p)
  1114.             pLynxFWIMData->lynxAsyncTxPCLDataList = (LynxAsyncTxPCLDataPtr) p;
  1115.         else
  1116.             status = memFullErr;
  1117.     }
  1118.  
  1119.     // Set up async transmit PCLs.
  1120.     if (status == noErr)
  1121.     {
  1122.         LynxFWIMCreateAsyncTxDummyPCL (pLynxFWIMData);
  1123.         LynxFWIMCreateAsyncTxDonePCLSegment (pLynxFWIMData);
  1124.         LynxFWIMCreateAsyncTxDataPCL (pLynxFWIMData);
  1125.     }
  1126.  
  1127.     // Create deferred task for handling bus resets.
  1128.     if (status == noErr)
  1129.     {
  1130.         status = FWCreateDeferredTask (&(pLynxFWIMData->busResetDeferredTaskID),
  1131.                                        LynxFWIMResetDeferredTask,
  1132.                                        pLynxFWIMData);
  1133.     }
  1134.  
  1135.     // Create deferred task for handling received async packets.
  1136.     if (status == noErr)
  1137.     {
  1138.         status = FWCreateDeferredTask (&(pLynxFWIMData->asyncReceiveDeferredTaskID),
  1139.                                        LynxFWIMDMAAsyncPCLDeferredTask,
  1140.                                        pLynxFWIMData);
  1141.     }
  1142.  
  1143.     // Create deferred task for handling received isoch packets.
  1144.     if (status == noErr)
  1145.     {
  1146.         status = FWCreateDeferredTask (&(pLynxFWIMData->isochReceiveDeferredTaskID),
  1147.                                        LynxFWIMDMAIsochReceivePCLDeferredTask,
  1148.                                        pLynxFWIMData);
  1149.     }
  1150.  
  1151.     // Create deferred task for handling transmitted isoch packets.
  1152.     if (status == noErr)
  1153.     {
  1154.         status = FWCreateDeferredTask (&(pLynxFWIMData->isochTransmitDeferredTaskID),
  1155.                                        LynxFWIMDMAIsochTransmitDeferredTask,
  1156.                                        pLynxFWIMData);
  1157.     }
  1158.  
  1159.     // Create deferred task for handling miscellaneous interrupts.
  1160.     if (status == noErr)
  1161.     {
  1162.         status = FWCreateDeferredTask (&(pLynxFWIMData->miscInterruptDeferredTaskID),
  1163.                                        LynxFWIMMiscInterruptDeferredTask,
  1164.                                        pLynxFWIMData);
  1165.     }
  1166.  
  1167.     // Install interrupt handler.
  1168.     if (status == noErr)
  1169.     {
  1170.         status = LynxFWIMInstallInterruptHandler (pLynxFWIMData);
  1171.     }
  1172.  
  1173.     // Use config space to enable bus mastering and memory space.
  1174.     if (status == noErr)
  1175.     {
  1176.         status = ExpMgrConfigWriteWord (
  1177.                     pFWIMRegEntryID, (LogicalAddress) cwCommand,
  1178.                     (cwCommandEnableBusMaster | cwCommandEnableMemorySpace));
  1179.     }
  1180.  
  1181.     FWDebugStr ((ConstStr255Param) "\pLynxFWIMInitialize: Start poking registers");
  1182.  
  1183.     if (status == noErr) status = LynxFWIMFullReset();
  1184.     
  1185.     FWDebugStr ((ConstStr255Param) "\pLynxFWIMInitialize: Done!");
  1186.  
  1187.     return (status);
  1188. }
  1189.  
  1190.  
  1191. ////////////////////////////////////////////////////////////////////////////////
  1192. //
  1193. // LynxFWIMFinalize
  1194. //
  1195. //   This is the FWIM finalizing proc.  It deallocates everything.
  1196. //
  1197.  
  1198. static OSStatus    LynxFWIMFinalize(
  1199.     FWIMFinalizeParamsPtr        pFWIMFinalizeParams)
  1200. {
  1201.     LynxFWIMDataPtr                pLynxFWIMData;
  1202.     OSStatus                    status = noErr;
  1203.  
  1204.     // Get our internal data.
  1205.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMFinalizeParams->fwimSpecificData;
  1206.  
  1207.     //zzz deallocate everything.
  1208.  
  1209.     return (status);
  1210. }
  1211.  
  1212.  
  1213. ////////////////////////////////////////////////////////////////////////////////
  1214. //
  1215. // LynxFWIMPollInterrupts
  1216. //
  1217. //   This proc checks for pending interrupts.
  1218. //
  1219.  
  1220. static OSStatus    LynxFWIMPollInterrupts(
  1221.     FWIMPollInterruptsParamsPtr    pFWIMPollInterruptsParams)
  1222. {
  1223.     OSStatus                    status = noErr;
  1224.  
  1225.     status = LynxFWIMDispatchInterrupts
  1226.                 ((LynxFWIMDataPtr) pFWIMPollInterruptsParams->fwimSpecificData);
  1227.  
  1228.     return (status);
  1229. }
  1230.  
  1231.  
  1232. ////////////////////////////////////////////////////////////////////////////////
  1233. //
  1234. // LynxFWIMGetRegisterBaseAddress
  1235. //
  1236. //   This proc uses the name registry to find the base address of the registers.
  1237. //
  1238.  
  1239. static OSStatus    LynxFWIMGetRegisterBaseAddress(
  1240.     LynxFWIMDataPtr                pLynxFWIMData)
  1241. {
  1242.     RegEntryIDPtr                pFWIMRegEntryID = &(pLynxFWIMData->FWIMRegEntryID);
  1243.     PCIAssignedAddressPtr        tempFWIMAddressesStorage = nil,
  1244.                                 pFWIMAddresses;
  1245.     Ptr                            pFWIMAddressesEnd;
  1246.     DeviceLogicalAddressPtr        tempFWIMLogicalAddressesStorage = nil,
  1247.                                 pFWIMLogicalAddresses;
  1248.     RegPropertyValueSize        propSize;
  1249.     UInt32                        assignedAddressesSize;
  1250.     Boolean                        done;
  1251.     OSStatus                    status = noErr;
  1252.  
  1253. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMGetRegisterBaseAddress");
  1254.  
  1255.     // Get assigned addresses property.
  1256.     status = RegistryPropertyGetSize
  1257.                 (pFWIMRegEntryID,
  1258.                  (RegPropertyNamePtr) kPCIAssignedAddressProperty,
  1259.                  &propSize);
  1260.  
  1261.     if (status == noErr)
  1262.     {
  1263.         tempFWIMAddressesStorage =
  1264.             (PCIAssignedAddressPtr) PoolAllocateResident (propSize, false);
  1265.         if (tempFWIMAddressesStorage == nil)
  1266.             status = memFullErr;
  1267.         else
  1268.             pFWIMAddresses = tempFWIMAddressesStorage;
  1269.     }
  1270.  
  1271.     if (status == noErr)
  1272.     {
  1273.         status = RegistryPropertyGet
  1274.                     (pFWIMRegEntryID,
  1275.                      (RegPropertyNamePtr) kPCIAssignedAddressProperty,
  1276.                      pFWIMAddresses,
  1277.                      &propSize);
  1278.         assignedAddressesSize = propSize;
  1279.     }
  1280.  
  1281.     // Get logical addresses property.
  1282.     if (status == noErr)
  1283.     {
  1284.         status = RegistryPropertyGetSize
  1285.                     (pFWIMRegEntryID,
  1286.                      (RegPropertyNamePtr) kAAPLDeviceLogicalAddress,
  1287.                      &propSize);
  1288.     }
  1289.  
  1290.     if (status == noErr)
  1291.     {
  1292.         tempFWIMLogicalAddressesStorage =
  1293.             (DeviceLogicalAddressPtr) PoolAllocateResident (propSize, false);
  1294.         if (tempFWIMLogicalAddressesStorage == nil)
  1295.             status = memFullErr;
  1296.         else
  1297.             pFWIMLogicalAddresses = tempFWIMLogicalAddressesStorage;
  1298.     }
  1299.  
  1300.     if (status == noErr)
  1301.     {
  1302.         status = RegistryPropertyGet
  1303.                     (pFWIMRegEntryID,
  1304.                      (RegPropertyNamePtr) kAAPLDeviceLogicalAddress,
  1305.                      pFWIMLogicalAddresses,
  1306.                      &propSize);
  1307.     }
  1308.  
  1309.     // Scan addresses until we find the one at config space 0x10.
  1310.     if (status == noErr)
  1311.     {
  1312.         pFWIMAddressesEnd = ((Ptr) pFWIMAddresses) + assignedAddressesSize;
  1313.         done = false;
  1314.  
  1315.         while ((((Ptr) pFWIMAddresses) < pFWIMAddressesEnd) && (!done))
  1316.         {
  1317.             if (pFWIMAddresses->registerNumber == 0x10)
  1318.             {
  1319.                 // There is a certain prototype system in which Open Firmware
  1320.                 // doesn't seem to work quite right yet.  If we find that the
  1321.                 // base register is zero, substitute another value for now.
  1322.                 
  1323.                 if (!*pFWIMLogicalAddresses)
  1324.                 {
  1325.                     pLynxFWIMData->pLynxRegisters = (LynxRegistersPtr) pFWIMAddresses->address.lo;
  1326.                     
  1327.                     sprintf (debugStr, "Base register 0, using %08lx", (long) pFWIMAddresses->address.lo);
  1328.                     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1329.                 }
  1330.                 else
  1331.                 {
  1332.                     pLynxFWIMData->pLynxRegisters = (LynxRegistersPtr) *pFWIMLogicalAddresses;
  1333.                 }
  1334.                 done = true;
  1335.             }
  1336.  
  1337.             pFWIMAddresses++;
  1338.             pFWIMLogicalAddresses++;
  1339.         }
  1340.  
  1341.         if (!done)
  1342.             status = paramErr;
  1343.     }
  1344.  
  1345.     // Deallocate temp storage.
  1346.     if (tempFWIMAddressesStorage != nil)
  1347.         PoolDeallocate ((LogicalAddress) tempFWIMAddressesStorage);
  1348.  
  1349.     if (tempFWIMLogicalAddressesStorage != nil)
  1350.         PoolDeallocate ((LogicalAddress) tempFWIMLogicalAddressesStorage);
  1351.  
  1352.     return (status);
  1353. }
  1354.  
  1355.  
  1356. ////////////////////////////////////////////////////////////////////////////////
  1357. //
  1358. // LynxFWIMInstallInterruptHandler
  1359. //
  1360. //   This proc installs the chip interrupt handler.
  1361. //
  1362.  
  1363. static OSStatus    LynxFWIMInstallInterruptHandler(
  1364.     LynxFWIMDataPtr                pLynxFWIMData)
  1365. {
  1366.     RegEntryIDPtr                pFWIMRegEntryID = &(pLynxFWIMData->FWIMRegEntryID);
  1367.     ISTProperty                    interruptSets;
  1368.     InterruptSetID                interruptSetID;
  1369.     InterruptMemberNumber        interruptMemberNumber;
  1370.     void                        *oldInterruptRefCon;
  1371.     InterruptHandler            oldInterruptHandler;
  1372.     InterruptEnabler            interruptEnabler;
  1373.     InterruptDisabler            interruptDisabler;
  1374.     RegPropertyValueSize        propSize;
  1375.     OSStatus                    status = noErr;
  1376.  
  1377. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMInstallInterruptHandler");
  1378.  
  1379.     // Get our interrupt set from the name registry.
  1380.     propSize = sizeof (ISTProperty);
  1381.     status = RegistryPropertyGet (pFWIMRegEntryID, kISTPropertyName,
  1382.                                   &interruptSets, &propSize);
  1383.     interruptSetID = interruptSets[kISTChipInterruptSource].setID;
  1384.     interruptMemberNumber = interruptSets[kISTChipInterruptSource].member;
  1385.  
  1386.     // Get the interrupt enabler and disabler for our chip interrupt set.
  1387.     if (status == noErr)
  1388.     {
  1389.         status = GetInterruptFunctions
  1390.                     (interruptSetID, interruptMemberNumber,
  1391.                      &oldInterruptRefCon, &oldInterruptHandler,
  1392.                      &interruptEnabler, &interruptDisabler);
  1393.     }
  1394.  
  1395.     // Install the refCon and interrupt handler for our chip interrupt set.
  1396.     if (status == noErr)
  1397.     {
  1398.         status = InstallInterruptFunctions
  1399.                     (interruptSetID, interruptMemberNumber,
  1400.                      pLynxFWIMData, (InterruptHandler) LynxFWIMInterruptHandler,
  1401.                      nil, nil);
  1402.     }
  1403.  
  1404.     // Add info to our FWIM Data record.
  1405.     if (status == noErr)
  1406.     {
  1407.         pLynxFWIMData->interruptSetMember.setID = interruptSetID;
  1408.         pLynxFWIMData->interruptSetMember.member = interruptMemberNumber;
  1409.         pLynxFWIMData->oldInterruptRefCon = oldInterruptRefCon;
  1410.         pLynxFWIMData->oldInterruptHandler = oldInterruptHandler;
  1411.         pLynxFWIMData->interruptEnabler = interruptEnabler;
  1412.         pLynxFWIMData->interruptDisabler = interruptDisabler;
  1413.     }
  1414.  
  1415.     return (status);
  1416. }
  1417.  
  1418.  
  1419. ////////////////////////////////////////////////////////////////////////////////
  1420. //
  1421. // LynxFWIMcrc16
  1422. //
  1423. // Compute the CRC-16 value of a block of quadlets.
  1424. // Adapted from Table 23 of IEEE 1212.
  1425. // Takes quadlet pointer and count of quadlets
  1426.  
  1427. static UInt16 LynxFWIMcrc16(
  1428.     UInt32                        *data,
  1429.     UInt32                        count)
  1430. {
  1431.     SInt32                        shift;
  1432.     UInt16                        sum, next = 0;
  1433.     UInt32                        doCount = count, *doData = data;
  1434.     
  1435.     while (doCount--)
  1436.     {
  1437.         for (shift = 28; shift >= 0; shift -= 4)        // 8 times, 4 bits each time
  1438.         {
  1439.             sum = ((next >> 12) ^ (*doData >> shift)) & 0x0f;        // get 4 bits
  1440.             next = (next << 4) ^ (sum << 12) ^ (sum << 5) ^ sum;    // apply them
  1441.         }
  1442.         doData++;
  1443.     }
  1444.     
  1445.     return next;
  1446. }
  1447.  
  1448.  
  1449. ////////////////////////////////////////////////////////////////////////////////
  1450. //
  1451. // LynxFWIMControlEEPROM
  1452. //
  1453. // Modify (up to) three EEPROM control bits:  Clock, Data, and Timer.
  1454. // There isn't currently any place we're called without the timer option.
  1455.  
  1456. static void LynxFWIMControlEEPROM(
  1457.     LynxFWIMDataPtr                pLynxFWIMData,
  1458.     UInt32                        clock,
  1459.     UInt32                        data,
  1460.     UInt32                        timer)
  1461. {
  1462.     UInt32                        eepromTemp;
  1463.     
  1464.     eepromTemp = pLynxFWIMData->pLynxRegisters->serialEEPROMControl;
  1465.     SynchronizeIO ();
  1466.     
  1467.     if (clock == kClockHi)
  1468.         eepromTemp |= EndianSwapImm32Bit (kLynxEEPCLK);
  1469.         else eepromTemp &= ~EndianSwapImm32Bit (kLynxEEPCLK);
  1470.  
  1471.     if (data != kNoData)
  1472.     {
  1473.         if (data == kDataHi)
  1474.             eepromTemp |= EndianSwapImm32Bit (kLynxEEPDAT);
  1475.             else eepromTemp &= ~EndianSwapImm32Bit (kLynxEEPDAT);
  1476.     }
  1477.     
  1478.     if (timer == kStartTimer)
  1479.         eepromTemp &= ~EndianSwapImm32Bit (kLynxTIMER_5USEC);
  1480.         else eepromTemp |= EndianSwapImm32Bit (kLynxTIMER_5USEC);
  1481.  
  1482.     pLynxFWIMData->pLynxRegisters->serialEEPROMControl = eepromTemp;
  1483.     SynchronizeIO ();
  1484. }
  1485.  
  1486.  
  1487. ////////////////////////////////////////////////////////////////////////////////
  1488. //
  1489. // LynxFWIMWaitForEEPROM
  1490. //
  1491. // Wait for a previously set timer to expire, then return the EEPROM data bit
  1492.  
  1493. static UInt32 LynxFWIMWaitForEEPROM(
  1494.     LynxFWIMDataPtr                pLynxFWIMData)
  1495. {
  1496.     UInt32                        e = 0;
  1497.         
  1498.     while (!(e & EndianSwapImm32Bit (kLynxTIMER_5USEC)))
  1499.     {
  1500.         e = pLynxFWIMData->pLynxRegisters->serialEEPROMControl;
  1501.         SynchronizeIO ();
  1502.     }
  1503.  
  1504.     return ((e & EndianSwapImm32Bit (kLynxEEPDAT)) != 0);
  1505. }
  1506.  
  1507.  
  1508. ////////////////////////////////////////////////////////////////////////////////
  1509. //
  1510. // LynxFWIMSendEEPROMBit
  1511. //
  1512. // Send one bit to the serial EEPROM.  To do this, assert the data bit, wait for it
  1513. // to be stable, then raise the clock signal for 5us to send the bit, then lower the
  1514. // clock signal.
  1515. // If we do these back to back we might be able to remove the final clock wait.
  1516.  
  1517. static void LynxFWIMSendEEPROMBit(
  1518.     LynxFWIMDataPtr                pLynxFWIMData,
  1519.     UInt32                        bit)
  1520. {
  1521.     int                            dataBit = bit ? kDataHi : kDataLo;
  1522.     
  1523.     // Set initial state
  1524.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, dataBit, kStartTimer);    
  1525.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1526.  
  1527.     // Raise clock to send data
  1528.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, dataBit, kStartTimer);    
  1529.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1530.  
  1531.     // Drop clock to end this bit
  1532.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, dataBit, kStartTimer);    
  1533.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1534. }
  1535.  
  1536.  
  1537. ////////////////////////////////////////////////////////////////////////////////
  1538. //
  1539. // LynxFWIMSendEEPROMByte
  1540. //
  1541. // Send one byte to the EEPROM, MSB first
  1542.  
  1543. static void LynxFWIMSendEEPROMByte(
  1544.     LynxFWIMDataPtr                pLynxFWIMData,
  1545.     UInt8                        sendByte)
  1546. {
  1547.     int                            i; 
  1548.     UInt8                        sendMe = sendByte;
  1549.     
  1550.     for (i = 0; i < 8; i++)
  1551.     {
  1552.         LynxFWIMSendEEPROMBit (pLynxFWIMData, sendMe >> 7);        // Send current MSB
  1553.         sendMe = sendMe << 1;                                    // Rotate next bit into MSB
  1554.     }
  1555. }
  1556.  
  1557.  
  1558. ////////////////////////////////////////////////////////////////////////////////
  1559. //
  1560. // LynxFWIMReadEEPROMBit
  1561. //
  1562.  
  1563. static UInt32 LynxFWIMReadEEPROMBit(
  1564.     LynxFWIMDataPtr                pLynxFWIMData)
  1565. {
  1566.     UInt32                        data;
  1567.     
  1568.     // When reading the data, we have to take the Data line Hi (tristate)
  1569.     // and then see which way the ROM pulls it (high or low)
  1570.     
  1571.     // Set initial state
  1572.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataHi, kStartTimer);    
  1573.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1574.  
  1575.     // Now take clock high to receive data
  1576.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kNoData, kStartTimer);
  1577.     data = LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1578.  
  1579.     // set clock low to end this bit
  1580.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kNoData, kStartTimer);
  1581.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1582.     
  1583.     return data;
  1584. }
  1585.  
  1586.  
  1587. ////////////////////////////////////////////////////////////////////////////////
  1588. //
  1589. // LynxFWIMReadEEPROMByte
  1590. //
  1591. // Read one byte from the EEPROM, MSB first
  1592.  
  1593. static UInt8 LynxFWIMReadEEPROMByte(
  1594.     LynxFWIMDataPtr                pLynxFWIMData)
  1595. {
  1596.     int                            i; 
  1597.     UInt8                        readByte = 0;
  1598.     
  1599.     for (i = 0; i < 8; i++)
  1600.         readByte = (readByte << 1) | LynxFWIMReadEEPROMBit (pLynxFWIMData);
  1601.     
  1602.     return readByte;
  1603. }
  1604.  
  1605.  
  1606. ////////////////////////////////////////////////////////////////////////////////
  1607. //
  1608. // LynxFWIMStartEEPROM
  1609. //
  1610. // Send a special "Start" signal to the EEPROM, by taking the data line
  1611. // low while holding the clock line high.
  1612.  
  1613. static void LynxFWIMStartEEPROM (
  1614.     LynxFWIMDataPtr                pLynxFWIMData)
  1615. {
  1616.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataHi, kStartTimer);
  1617.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1618.     
  1619.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataHi, kStartTimer);
  1620.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1621.     
  1622.     // While clock is still high, take data low - this signals a "start"
  1623.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataLo, kStartTimer);
  1624.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1625.     
  1626.     // Now take clock low to signal end of "start"
  1627.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataLo, kStartTimer);
  1628.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1629. }
  1630.  
  1631.  
  1632. ////////////////////////////////////////////////////////////////////////////////
  1633. //
  1634. // LynxFWIMStopEEPROM
  1635. //
  1636. // Send a special "Stop" signal to the EEPROM, by taking the data line
  1637. // low while holding the clock line high.
  1638.  
  1639. static void LynxFWIMStopEEPROM (
  1640.     LynxFWIMDataPtr                pLynxFWIMData)
  1641. {
  1642.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataLo, kStartTimer);
  1643.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1644.     
  1645.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataLo, kStartTimer);
  1646.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1647.     
  1648.     // While clock is still high, take data high - this signals a "stop"
  1649.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockHi, kDataHi, kStartTimer);
  1650.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1651.     
  1652.     // Now take clock low to signal end of "stop"
  1653.     LynxFWIMControlEEPROM (pLynxFWIMData, kClockLo, kDataHi, kStartTimer);
  1654.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1655. }
  1656.  
  1657.  
  1658. ////////////////////////////////////////////////////////////////////////////////
  1659. //
  1660. // LynxFWIMProcessEEPROM
  1661. //
  1662. // Read data out of the Lynx serial EEPROM, to determine our Unique ID, and
  1663. // some configuration info like how much SRAM we have on board.  This is lots
  1664. // of fun because we have to manually clock the EEPROM by wiggling the clock
  1665. // and data lines around under software control.
  1666. //
  1667. // This takes roughly 30 milliseconds, if the Lynx 5 microsecond timer is accurate
  1668.  
  1669. // still to do:
  1670. // checksum
  1671.  
  1672. static void LynxFWIMProcessEEPROM(
  1673.     LynxFWIMDataPtr                pLynxFWIMData)
  1674. {
  1675.     OSStatus                    status = noErr;
  1676.     UInt32                        eepromState, readQuad, scanQuad, scanKey;
  1677.     SInt32                        scanLen, scanPos, modulePos;
  1678.     LynxEEPROMBasePtr            eepromBase;
  1679.     LynxEEPROMInfoPtr            eepromInfo;
  1680.  
  1681.     eepromBase = (LynxEEPROMBasePtr) pLynxFWIMData->eepromData;
  1682.     eepromInfo = &(pLynxFWIMData->eepromInfo);
  1683.     
  1684.     // Prepare invalid/default values in case something goes wrong
  1685.     
  1686.     pLynxFWIMData->eepromValid = false;
  1687.     modulePos = 0;                                        // Illegal value
  1688.     eepromInfo->module_Vendor_Id = 0xffffffff;            // Legal values are only 24 bits
  1689.     eepromInfo->module_Hardware_Version = 0xffffffff;    // same
  1690.     eepromInfo->node_Hardware_Version = 0xffffffff;        // same
  1691.     eepromInfo->sram_Quads = 0;                            // Assume 0 if key not found
  1692.     eepromInfo->auxRam_Quads = 0;                        // same
  1693.     eepromInfo->aux_Device = 0;                            // same
  1694.     
  1695.     // We can skip all this if the EEPROM is missing or broken:
  1696.     
  1697.     eepromState = EndianSwap32Bit (pLynxFWIMData->pLynxRegisters->serialEEPROMControl);
  1698.     if (eepromState & (kLynxEEPERR | kLynxEEPCHKERR | kLynxNOTPRS))
  1699.         return;
  1700.     
  1701.     // Reset the EEPROM control register & state
  1702.     
  1703.     pLynxFWIMData->pLynxRegisters->serialEEPROMControl =
  1704.         EndianSwapImm32Bit (kLynxEEPENA | kLynxEEPDAT | kLynxTIMER_5USEC);
  1705.     SynchronizeIO ();    
  1706.     LynxFWIMWaitForEEPROM (pLynxFWIMData);
  1707.     
  1708.     // First we send a special "start" signal to get the EEPROM's attention.
  1709.  
  1710.     LynxFWIMStartEEPROM (pLynxFWIMData);
  1711.  
  1712.     // In order to do a random read, we pretend to initiate a write.  That
  1713.     // sets the address at which the EEPROM will either read or write.
  1714.     
  1715.     // The WRITE message is formed like this:    10100000  == 0xa0
  1716.     //      Identifies NM24Cxx serial EEPROM ----> 1010   0 <--- 0 indicates WRITE
  1717.     //      Indicates device/block (page) address ---> 000
  1718.  
  1719.     LynxFWIMSendEEPROMByte (pLynxFWIMData, 0xa0);            // WRITE command 01010000
  1720.     LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);                // strobe for Ack
  1721.  
  1722.     LynxFWIMSendEEPROMByte (pLynxFWIMData, 0x00);            // Data address 00000000
  1723.     LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);                // strobe for Ack
  1724.  
  1725.     // Now we're done with the dummy write.  Send another "start" condition.
  1726.  
  1727.     LynxFWIMStartEEPROM (pLynxFWIMData);
  1728.  
  1729.     // READ command is same as WRITE command above, except for last bit.
  1730.  
  1731.     LynxFWIMSendEEPROMByte (pLynxFWIMData, 0xa1);            // READ command 01010001
  1732.     
  1733.     // Read the minimum-sized EEPROM (256 bytes) into memory.
  1734.     
  1735.     for (scanPos = 0; scanPos < kLynxMinEEPROMQuads; scanPos++)
  1736.     {
  1737.         LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);    // ack previous Send/Read
  1738.         
  1739.         readQuad = LynxFWIMReadEEPROMByte (pLynxFWIMData);
  1740.         LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);    // ack
  1741.         
  1742.         readQuad = (readQuad << 8) | LynxFWIMReadEEPROMByte (pLynxFWIMData);
  1743.         LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);    // ack
  1744.         
  1745.         readQuad = (readQuad << 8) | LynxFWIMReadEEPROMByte (pLynxFWIMData);
  1746.         LynxFWIMSendEEPROMBit (pLynxFWIMData, 0);    // ack
  1747.         
  1748.         readQuad = (readQuad << 8) | LynxFWIMReadEEPROMByte (pLynxFWIMData);
  1749.         
  1750.         pLynxFWIMData->eepromData[scanPos] = readQuad;
  1751.     }
  1752.     
  1753.     // Now we are supposed to send a STOP condition.
  1754.  
  1755.     LynxFWIMStopEEPROM (pLynxFWIMData);
  1756.  
  1757.     // We're done with the EEPROM.  Extract some info from what we got.
  1758.     
  1759.     if (eepromBase->crcLen > kLynxMinEEPROMQuads)        // Protect against bogus lengths
  1760.         return;
  1761.  
  1762.     if (eepromBase->crc !=
  1763.         LynxFWIMcrc16 ((UInt32 *) eepromBase->busInfoBlock, (UInt32) eepromBase->crcLen))
  1764.         return;
  1765.     
  1766.     // If we passed CRC on the Bus Info block, declare the EEPROM to be valid.
  1767.     // This means that at least the unique ID is present and passes CRC, which
  1768.     // is all we currently use anyway.
  1769.     
  1770.     pLynxFWIMData->eepromValid = true;
  1771.     BlockCopy ((Ptr) &(eepromBase->busInfoBlock), (Ptr) &(eepromInfo->busInfoBlock), 16);
  1772.     
  1773.     scanLen = eepromBase->romData[0] >> 16;                // Root directory length in quadlets
  1774.  
  1775.     if (scanLen > kLynxMinEEPROMQuads)                    // Protect against bogus lengths
  1776.         return;
  1777.  
  1778.     if ((eepromBase->romData[0] & 0xffff) !=
  1779.         LynxFWIMcrc16 (&(eepromBase->romData[1]), scanLen))
  1780.         return;
  1781.         
  1782.     // Scan the root directory
  1783.     for (scanPos = 1; scanPos <= scanLen; scanPos++)
  1784.     {
  1785.         scanQuad = eepromBase->romData[scanPos];
  1786.         scanKey = scanQuad >> 24;
  1787.         
  1788.         switch (scanKey)
  1789.         {
  1790.             case kLynxEEPROMKeyModuleVendorID:
  1791.                 eepromInfo->module_Vendor_Id = scanQuad & 0xffffff;
  1792.                 break;
  1793.                 
  1794.             case kLynxEEPROMKeyModuleHardwareVersion:
  1795.                 eepromInfo->module_Hardware_Version = scanQuad & 0xffffff;
  1796.                 break;
  1797.                 
  1798.             case kLynxEEPROMKeyNodeHardwareVersion:
  1799.                 eepromInfo->node_Hardware_Version = scanQuad & 0xffffff;
  1800.                 break;
  1801.                 
  1802.             case kLynxEEPROMKeyModuleDependentInfo:
  1803.                 modulePos = scanPos + (scanQuad & 0xffffff);
  1804.                 break;
  1805.                 
  1806.             default: break;
  1807.         }
  1808.     }
  1809.     
  1810.     // Scan the module-dependent directory, if found
  1811.     if (modulePos)
  1812.     {
  1813.         scanLen = eepromBase->romData[modulePos] >> 16;        // Module dep dir length in quadlets
  1814.  
  1815.         if (scanLen > kLynxMinEEPROMQuads)                    // Protect against bogus lengths
  1816.             return;
  1817.  
  1818.         if ((eepromBase->romData[modulePos] & 0xffff) !=
  1819.             LynxFWIMcrc16 (&(eepromBase->romData[modulePos + 1]), scanLen))
  1820.             return;
  1821.         
  1822.         for (scanPos = 1; scanPos <= scanLen; scanPos++)
  1823.         {
  1824.             scanQuad = eepromBase->romData[modulePos + scanPos];
  1825.             scanKey = scanQuad >> 24;
  1826.             
  1827.             switch (scanKey)
  1828.             {
  1829.                 case kLynxEEPROMKeySramQuads:
  1830.                     eepromInfo->sram_Quads = scanQuad & 0xffffff;
  1831.                     break;
  1832.  
  1833.                 case kLynxEEPROMKeyAuxRamQuads:
  1834.                     eepromInfo->auxRam_Quads = scanQuad & 0xffffff;
  1835.                     break;
  1836.                     
  1837.                 case kLynxEEPROMKeyAuxDevice:
  1838.                     eepromInfo->aux_Device = scanQuad & 0xffffff;
  1839.                     break;
  1840.                     
  1841.                 default:
  1842.                     break;
  1843.             }
  1844.         }
  1845.     }
  1846.  
  1847. #if 0    
  1848.     sprintf (debugStr, "EEPROM  Node Vendor ID %06lx   Chip ID %02lx%08lx",
  1849.              (long) eepromInfo->busInfoBlock[2] >> 8,
  1850.              (long) eepromInfo->busInfoBlock[2] & 0xff,
  1851.              (long) eepromInfo->busInfoBlock[3]);
  1852.     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1853.  
  1854.     sprintf (debugStr, "EEPROM  Mod Vendor ID %06lx   Mod HW Vers %06lx   Node HW Vers %06lx",
  1855.              (long) eepromInfo->module_Vendor_Id,
  1856.              (long) eepromInfo->module_Hardware_Version,
  1857.              (long) eepromInfo->node_Hardware_Version);
  1858.     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1859.  
  1860.     sprintf (debugStr, "EEPROM  SRAM size %06lx (q)   AUX RAM size %06lx (q)   AUX Device %06lx",
  1861.              (long) eepromInfo->sram_Quads,
  1862.              (long) eepromInfo->auxRam_Quads,
  1863.              (long) eepromInfo->aux_Device);
  1864.     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  1865. #endif
  1866.  
  1867.     return;
  1868. }
  1869.  
  1870.  
  1871. ////////////////////////////////////////////////////////////////////////////////
  1872. //
  1873. // LynxFWIMFullReset
  1874. //
  1875. //   This function flips the SWRST bit to fully reset the Lynx card,
  1876. //   Then re-establishes interrupts, DMA, etc.
  1877. //   This is used both during FWIM Install and any time the card jams up.
  1878. //   As far as I know this does not cause a bus reset.
  1879. //
  1880.  
  1881. static OSStatus    LynxFWIMFullReset(void)
  1882. {
  1883.     LynxFWIMDataPtr                pLynxFWIMData = HACKdata;
  1884.     LynxRegistersPtr            pLynxRegs;
  1885.     UInt32                        nodeAddress;
  1886.     OSStatus                    status = noErr;
  1887.     static UInt32                firstTime = 1;
  1888.     UInt32                        physicalID;
  1889.     UInt32                        oldNodeID;
  1890.  
  1891. //    FWDebugStr ((ConstStr255Param) "\p(Lynx) LynxFWIMFullReset");
  1892.  
  1893. // Do we need to cancel any timers?!?
  1894.  
  1895.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  1896.     oldNodeID = pLynxRegs->busNumberNodeNumber;
  1897.     
  1898.     // Reset everything:
  1899.     pLynxRegs->miscControl = EndianSwapImm32Bit (kLynxSWRST);
  1900.     SynchronizeIO ();
  1901.     if (pLynxRegs->miscControl & EndianSwapImm32Bit (kLynxSWRST))
  1902.         FWDebugStr ((ConstStr255Param) "\pLynxFWIMFullReset: Should have waited for SWRST");
  1903.     
  1904.     // Lynx errata advises this:
  1905.     pLynxRegs->miscControl = EndianSwapImm32Bit (kLynxENA_POST_WR | kLynxENA_SLV_BURST);
  1906.     SynchronizeIO ();
  1907.  
  1908.     if (firstTime) LynxFWIMProcessEEPROM (pLynxFWIMData);
  1909.     
  1910.     // Set up the FIFOs.
  1911.     LynxFWIMSetupFIFOs (pLynxFWIMData);
  1912.  
  1913.     // Set up DMA for packet reception
  1914.     
  1915.     LynxFWIMPrepareAsyncDMA (pLynxFWIMData, kAsyncDMA);
  1916.  
  1917.     // Some information about the DMA comparators
  1918.     // (The Lynx 0.10 spec is very confusing)
  1919.     
  1920.     // This makes all self-ID, async, and isoch arrive on one DMA channel (0)
  1921.     // including async packets not directed to our node/bus ID:
  1922.     //   Set all enables and values to 0, except for 0x0B0C: RCV_SELF_ID_EN | EN_CH_COMPARE
  1923.     
  1924.     // For the same as above on channel 0, except with all isoch going to channel
  1925.     // 1 instead, set 0x0B04 to 0x000000A0 ('Async tcode encoding ("normal") -> GRF')
  1926.     // Also turn on EN_CH_COMPARE for channel 1
  1927.     
  1928.     // Same as previous, but send async that isn't for our own node onto channel 1
  1929.     // along with all the isochronous packets:
  1930.     // set 0x0B0C to RCV_SELF_ID_EN | EN_CH_COMPARE | DEST_ID_SEL (00001)
  1931.     
  1932.     // Here's what we actually do - all of the above, plus, restrict channel 1 to
  1933.     // isoch only, so we no longer receive async packets that aren't for our node.
  1934.     // Set 0x0B14 to 0x00000090 ('Iso tcode encoding ("normal") -> GRF')
  1935.  
  1936.     // This controls retries ONLY for busy acknowledge, not data errors or no-ack
  1937.     // cases.  Busy ack means the other node really is there, but just can't handle
  1938.     // our packet right now (possibly because they experienced a FIFO overflow).
  1939.     // It's probably good to try a bunch of times, because busy is a rare case, and
  1940.     // we always expect to get through eventually.
  1941.     
  1942.     // Mark up to 32 retries, 16 cycles apart (1/15 second max delay)
  1943.     pLynxRegs->retryCountInterval = EndianSwapImm32Bit (0x00001020);
  1944.     SynchronizeIO ();
  1945.     
  1946.     // Enable Receiver and Transmitter
  1947.     LynxFWIMSetLinkControl (pLynxFWIMData,
  1948.                             kLynxTX_ISO_EN |
  1949.                             kLynxRX_ISO_EN |
  1950.                             kLynxTX_ASYNC_EN |
  1951.                             kLynxRX_ASYNC_EN |
  1952.                             kLynxRCV_COMP_VALID);
  1953.     
  1954.     if (firstTime)
  1955.     {
  1956.         // Get physical ID.
  1957.         NoPhyReset = 1;
  1958.         physicalID = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhyPhysicalIDAddress);
  1959.         NoPhyReset = 0;
  1960.         physicalID = (physicalID & kLynxPhyPhysicalID) >> kLynxPhyPhysicalIDPhase;
  1961.     
  1962.         // Set our bus number to default 0x3FF.
  1963.         //zzz how will we determine correct bus number.
  1964.     
  1965.         nodeAddress = EndianSwap32Bit (pLynxRegs->busNumberNodeNumber);
  1966.         nodeAddress =    (nodeAddress & (~kLynxBUS_ID)) |
  1967.                         ((0x3FF << kLynxBUS_IDPhase) & kLynxBUS_ID);
  1968.         nodeAddress =    (nodeAddress & (~kLynxNODE_ID)) |
  1969.                         ((physicalID << kLynxNODE_IDPhase) & kLynxNODE_ID);
  1970.         pLynxRegs->busNumberNodeNumber = EndianSwap32Bit (nodeAddress);
  1971.         SynchronizeIO ();
  1972.     }
  1973.     else
  1974.     {
  1975.         pLynxRegs->busNumberNodeNumber = oldNodeID;
  1976.         SynchronizeIO ();
  1977.     }
  1978.     
  1979. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMFullReset: Enable interrupts");
  1980.  
  1981.     if (firstTime)
  1982.     {
  1983.         // Enable chip interrupts.
  1984.         if (status == noErr)
  1985.         {
  1986.             (*(pLynxFWIMData->interruptEnabler)) (pLynxFWIMData->interruptSetMember,
  1987.                                                 pLynxFWIMData->oldInterruptRefCon);
  1988.         }
  1989.     }
  1990.  
  1991.     // Enable interrupts for bus resets, phy registers, and DMA PCL ints
  1992.     {
  1993.         pLynxRegs->linkInterruptEnable =
  1994.             EndianSwapImm32Bit (kLynxLINK_INT |
  1995.                                 kLynxPHY_BUSRESET |
  1996.                                 kLynxPHY_REG_RCVD);
  1997.         SynchronizeIO ();
  1998.  
  1999.         // Enable additional interrupts only if we are running FireBug.
  2000.         // Interrupts will be reported to FireBug.
  2001.         // Normally there's nothing we can do about these interrupts.
  2002.         
  2003. #ifdef LynxFireBug
  2004.         pLynxRegs->linkInterruptEnable |=
  2005.             EndianSwapImm32Bit (kLynxPHY_TIME_OUT |
  2006.                                 kLynxIT_STUCK |
  2007.                                 kLynxAT_STUCK |
  2008.                                 kLynxTC_ERR |
  2009.                                 kLynxITF_UNDER_FLOW |
  2010.                                 kLynxATF_UNDER_FLOW |
  2011.                                 kLynxIARB_FAILED);
  2012.         SynchronizeIO ();
  2013.         
  2014.         // Note:  Checking for CYC_LOST is tricky.  We'll get 8000/second
  2015.         // unless we're cycle master or someone else is.  There can be
  2016.         // periods with no cycle master, and, sending out the message about
  2017.         // the interrupts repeatedly could prevent us from establishing a
  2018.         // new cycle master.
  2019.         
  2020.         // Checking for CYC_ARB_FAILED is also tricky.  It seems to indicate
  2021.         // that the bus was not idle when the cycle timer rolled over.  This
  2022.         // means that the cycle start packet was delayed, not lost.  That may
  2023.         // not be of great interest.
  2024.         
  2025.         // Header Error interrupt is broken on revA parts
  2026.         
  2027.         if ((pLynxRegs->configClassRevID >> 24) == 0)
  2028.             pLynxRegs->linkInterruptEnable |= EndianSwapImm32Bit (kLynxHDR_ERR);
  2029.         SynchronizeIO ();
  2030.  
  2031. #endif
  2032.  
  2033.         pLynxRegs->pciInterruptEnable =
  2034.             EndianSwapImm32Bit (kLynxINT_PEND |
  2035.                                 kLynxP1394_INT |
  2036.                                 kLynxDMA0_PCL |
  2037.                                 kLynxDMA2_PCL |
  2038.                                 kLynxDMA3_PCL);
  2039.         SynchronizeIO ();
  2040.     }
  2041.     
  2042.     // Enable Cycle Timer.
  2043.     {
  2044.         LynxFWIMSetLinkControl
  2045.             (pLynxFWIMData, EndianSwap32Bit (pLynxRegs->linkControl) | kLynxCYCTIMEREN);
  2046.     }
  2047.  
  2048.     if (firstTime)
  2049.     {
  2050.         UInt8                        phyReg;
  2051.     
  2052.         // Initiate bus reset.
  2053.         if (status == noErr)
  2054.         {
  2055.             NoPhyReset = 1;
  2056.             phyReg = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhyIBRAddress);
  2057.             phyReg |= kLynxPhyIBR;
  2058.             LynxFWIMWritePhyRegister (pLynxRegs, kLynxPhyIBRAddress, phyReg);
  2059.             NoPhyReset = 0;
  2060.         }
  2061.     }
  2062.     
  2063. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMFullReset: Survived!");
  2064.  
  2065.     firstTime = 0;
  2066.     return (0);
  2067. }
  2068.  
  2069.  
  2070. ////////////////////////////////////////////////////////////////////////////////
  2071. //
  2072. // LynxFWIMExceptionHandler
  2073. //
  2074. //   This proc handles exceptions.
  2075. //
  2076.  
  2077. static OSStatus    LynxFWIMExceptionHandler(
  2078.     ExceptionInformationPowerPC    *theException)
  2079. {
  2080.     OSStatus                    status = noErr;
  2081.  
  2082.     FWDebugStr ((ConstStr255Param) "\pLynxFWIMExceptionHandler");
  2083.  
  2084.     return (status);
  2085. }
  2086.  
  2087.  
  2088. ////////////////////////////////////////////////////////////////////////////////
  2089. //
  2090. // LynxFWIMInterruptHandler
  2091. //
  2092. //   This is the handler proc for chip interrupts.
  2093. //
  2094.  
  2095. static InterruptMemberNumber    LynxFWIMInterruptHandler(
  2096.     InterruptSetMember            interruptSetMember,
  2097.     void                        *interruptRefCon,
  2098.     UInt32                        interruptCount)
  2099. {
  2100.     LynxFWIMDispatchInterrupts ((LynxFWIMDataPtr) interruptRefCon);
  2101.  
  2102.     return (kIsrIsComplete);
  2103. }
  2104.  
  2105.  
  2106. ////////////////////////////////////////////////////////////////////////////////
  2107. //
  2108. // LynxFWIMDispatchInterrupts
  2109. //
  2110. //   This proc dispatches any pending interrupts.
  2111. //
  2112.  
  2113. static OSStatus    LynxFWIMDispatchInterrupts(
  2114.     LynxFWIMDataPtr                pLynxFWIMData)
  2115. {
  2116.     LynxRegistersPtr            pLynxRegs;
  2117.     UInt32                        interruptStatus, interruptStatusLittleEndian;
  2118.     OSStatus                    status = noErr;
  2119.  
  2120.     // Get our register base address.
  2121.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2122.  
  2123.     // Read PCI interrupt status register.
  2124.     interruptStatusLittleEndian = pLynxRegs->pciInterruptStatus;
  2125.     interruptStatus = EndianSwap32Bit (interruptStatusLittleEndian);
  2126.  
  2127.     // Note - there are lots of kinds of ints other than 1394 and DMA
  2128.     // that can happen.  We'll probably want to catch some of them.
  2129.     
  2130.     // Check for each type of supported interrupt.
  2131.     if (interruptStatus & kLynxINT_PEND)
  2132.     {
  2133.         // Check for link interrupt.  Could be a reset, must do that first
  2134.         if (interruptStatus & kLynxP1394_INT)
  2135.             LynxFWIMHandleLinkInterrupt (pLynxFWIMData);
  2136.  
  2137.         // Check for DMA 0 PCL interrupt.
  2138.         if (interruptStatus & kLynxDMA0_PCL)
  2139.             LynxFWIMHandleDMAAsyncPCLInterrupt (pLynxFWIMData);
  2140.                         
  2141.         // Check for DMA 2 PCL interrupt.
  2142.         if (interruptStatus & kLynxDMA2_PCL)
  2143.             LynxFWIMHandleDMAIsochReceivePCLInterrupt (pLynxFWIMData);
  2144.                         
  2145.         // Check for DMA 3 PCL interrupt.
  2146.         if (interruptStatus & kLynxDMA3_PCL)
  2147.             LynxFWIMHandleDMAIsochTransmitPCLInterrupt (pLynxFWIMData);
  2148.                         
  2149.     }
  2150.  
  2151.     // Clear the interrupts.
  2152.     pLynxRegs->pciInterruptStatus = interruptStatusLittleEndian;
  2153.     SynchronizeIO ();
  2154.  
  2155.     return (status);
  2156. }
  2157.  
  2158.  
  2159. ////////////////////////////////////////////////////////////////////////////////
  2160. //
  2161. // LynxFWIMHandleDMAAsyncPCLInterrupt
  2162. //
  2163. //   This proc handles DMA PCL (Async) interrupts.
  2164. //
  2165.  
  2166. static void LynxFWIMHandleDMAAsyncPCLInterrupt(
  2167.     LynxFWIMDataPtr                pLynxFWIMData)
  2168. {    
  2169.     OSStatus                    status = noErr;
  2170.  
  2171.     if (!(pLynxFWIMData->asyncReceiveDTScheduled))
  2172.     {
  2173.         status = FWScheduleDeferredTask (pLynxFWIMData->asyncReceiveDeferredTaskID, nil);
  2174.  
  2175.         if (status == noErr)
  2176.             pLynxFWIMData->asyncReceiveDTScheduled = true;
  2177.     }
  2178. }
  2179.  
  2180.  
  2181. ////////////////////////////////////////////////////////////////////////////////
  2182. //
  2183. // LynxFWIMHandleDMAIsochReceivePCLInterrupt
  2184. //
  2185. //   This proc handles interrupts sent by PCLs on channel 2 receiving isoch data.
  2186. //
  2187.  
  2188. static void LynxFWIMHandleDMAIsochReceivePCLInterrupt(
  2189.     LynxFWIMDataPtr                pLynxFWIMData)
  2190. {
  2191.     OSStatus                    status = noErr;
  2192.  
  2193.     if (!(pLynxFWIMData->isochReceiveDTScheduled))
  2194.     {
  2195.         status = FWScheduleDeferredTask (pLynxFWIMData->isochReceiveDeferredTaskID, nil);
  2196.  
  2197.         if (status == noErr)
  2198.             pLynxFWIMData->isochReceiveDTScheduled = true;
  2199.     }
  2200. }
  2201.  
  2202.  
  2203. ////////////////////////////////////////////////////////////////////////////////
  2204. //
  2205. // LynxFWIMHandleDMAIsochTransmitPCLInterrupt
  2206. //
  2207. //   This proc handles interrupts sent by PCLs on channel 3 transmitting isoch data.
  2208. //
  2209.  
  2210. static void LynxFWIMHandleDMAIsochTransmitPCLInterrupt(
  2211.     LynxFWIMDataPtr                pLynxFWIMData)
  2212. {
  2213.     OSStatus                    status = noErr;
  2214.  
  2215.     if (!(pLynxFWIMData->isochTransmitDTScheduled))
  2216.     {
  2217.         status = FWScheduleDeferredTask (pLynxFWIMData->isochTransmitDeferredTaskID, nil);
  2218.  
  2219.         if (status == noErr)
  2220.             pLynxFWIMData->isochTransmitDTScheduled = true;
  2221.     }
  2222. }
  2223.  
  2224.  
  2225. ////////////////////////////////////////////////////////////////////////////////
  2226. //
  2227. // LynxFWIMHandleLinkInterrupt
  2228. //
  2229. //   This proc handles 1394-specific interrupts (bus reset, GRF overflow).
  2230. //
  2231.  
  2232. static UInt32 flushCount = 0;
  2233.  
  2234. static void LynxFWIMHandleLinkInterrupt(
  2235.     LynxFWIMDataPtr                pLynxFWIMData)
  2236. {
  2237.     LynxRegistersPtr            pLynxRegs;
  2238.     UInt32                        interrupt, interruptLittleEndian, mask;
  2239.     UInt32                        handled = 0;
  2240.  
  2241.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2242.  
  2243.     interruptLittleEndian = pLynxRegs->linkInterruptStatus;
  2244.     interrupt = EndianSwapImm32Bit (interruptLittleEndian);
  2245.  
  2246.     // Mask out disabled interrupts.
  2247.     mask = EndianSwap32Bit (pLynxRegs->linkInterruptEnable) | kLynxLINK_INT;
  2248.     interrupt &= mask;
  2249.  
  2250.     // Check for each type of supported interrupt.
  2251.     if (interrupt & kLynxLINK_INT)
  2252.     {
  2253.         // Check for reset interrupt.
  2254.         if (interrupt & kLynxPHY_BUSRESET)
  2255.         {
  2256.             LynxFWIMHandleResetInterrupt (pLynxFWIMData);
  2257.         }
  2258.                         
  2259.         // Check for phy register interrupt.
  2260.         if (interrupt & kLynxPHY_REG_RCVD)
  2261.         {
  2262.             LynxFWIMHandlePhyRegRcvdInterrupt (pLynxFWIMData);
  2263.         }
  2264.                         
  2265.         // Check for GRF overflow interrupt.
  2266.         if ((interrupt & kLynxGRF_OVER_FLOW) ||
  2267.             (interrupt & kLynxSNTRJ))
  2268.         {
  2269. // This needs work, and its own function.  Redoing the DMA prep may take too long, too.
  2270. //zzz do we really need to do anything with GRF overflow.
  2271. //zzz flushing the GRF seems to only cause problems.
  2272.             FWDebugStr ((ConstStr255Param) "\pLynxFWIMHandleLinkInterrupt - GRF OVERFLOW ###");
  2273.         }
  2274.  
  2275. #ifdef LynxFireBug
  2276.         if (!(interrupt & kLynxPHY_BUSRESET))
  2277.         {
  2278.             LynxFWIMHandleMiscInterrupt (pLynxFWIMData);
  2279.         }
  2280. #endif
  2281.     }
  2282.  
  2283.     // Clear the interrupts.
  2284.     pLynxRegs->linkInterruptStatus = interruptLittleEndian;
  2285.     SynchronizeIO ();
  2286. }
  2287.  
  2288.  
  2289. ////////////////////////////////////////////////////////////////////////////////
  2290. //
  2291. // LynxFWIMHandleResetInterrupt
  2292. //
  2293. //   This proc handles bus reset interrupts.
  2294. //zzz must be able to handle two resets happening before we process one.
  2295. //
  2296.  
  2297. static void LynxFWIMHandleResetInterrupt(
  2298.     LynxFWIMDataPtr                pLynxFWIMData)
  2299. {
  2300.     LynxRegistersPtr            pLynxRegs;
  2301.     OSStatus                    status = noErr;
  2302.  
  2303.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2304.     
  2305.     // One possible remaining thorn.  If we disable the comparator, can we receive
  2306.     // self-IDs?  [Evidently the self-IDs still arrive OK]
  2307.     
  2308.     // When we get a reset interrupt, the async transmitter and receiver have been disabled.
  2309.     // We can't accept (or ack) packets until we know our new node number, and that won't
  2310.     // happen until about 150 microseconds from now, when we get the PHY REG RCVD interrupt.
  2311.     // We can't enable the receiver until we know this number, because if we do, we'll send
  2312.     // acks to packets directed at some other node (if our node ID changed).
  2313.     
  2314.     // So, disable the async receive comparator.  This prevents acks of any kind.
  2315.     // But enable the async receiver.  This is for race control.  By the time we receive
  2316.     // the PHY register update, there could have been another bus reset, and if we're
  2317.     // unlucky we get them out of order and load the wrong value.  A second bus reset
  2318.     // will disable the receiver, unless we come through this handler again, making it
  2319.     // safe to load a stale node ID.
  2320.         
  2321.     // Disable comparator
  2322.     pLynxRegs->dmaComparator[kAsyncDMA].mask1 &= ~EndianSwapImm32Bit (kLynxEN_CH_COMPARE);
  2323.     SynchronizeIO ();
  2324.     
  2325.     // Enable async receiver
  2326.     LynxFWIMSetLinkControl (pLynxFWIMData, EndianSwap32Bit (pLynxRegs->linkControl) | kLynxRX_ASYNC_EN);
  2327.  
  2328.     // Invalidate bus generation number.
  2329.     pLynxFWIMData->generationValid = false;
  2330.  
  2331.     // Process the reset.
  2332.     status = FWProcessBusReset (pLynxFWIMData->fwimID);
  2333.  
  2334.     // Schedule deferred task to handle reset.
  2335.     if (!(pLynxFWIMData->busResetDTScheduled))
  2336.     {
  2337.         status = FWScheduleDeferredTask (pLynxFWIMData->busResetDeferredTaskID, nil);
  2338.  
  2339.         if (status == noErr)
  2340.             pLynxFWIMData->busResetDTScheduled = true;
  2341.     }
  2342. }
  2343.  
  2344.  
  2345. ////////////////////////////////////////////////////////////////////////////////
  2346. //
  2347. // LynxFWIMHandlePhyRegRcvdInterrupt
  2348. //
  2349. //   This proc handles phy register receive interrupts.
  2350. //   Any time we get register 0, load the nodeID register.
  2351. //   This only really matters after a bus reset, but is harmless at other times.
  2352. //
  2353.  
  2354. static void LynxFWIMHandlePhyRegRcvdInterrupt(
  2355.     LynxFWIMDataPtr                pLynxFWIMData)
  2356. {
  2357.     LynxRegistersPtr            pLynxRegs;
  2358.     OSStatus                    status = noErr;
  2359.     UInt32                        phyData, busNodeID, newNodeID;
  2360.  
  2361.     // This happens about 150 microseconds after a bus reset, when the PHY sends
  2362.     // register zero automatically.  That's when we learn our new node ID, so we
  2363.     // interrupt to this function, and load that ID into register 0xF00.  Now we
  2364.     // can send acks for packets directed at us, so we turn the comparator back
  2365.     // on and try to start receiving packets.
  2366.     
  2367.     // If there has been another bus reset after the PHY interrupt but before we
  2368.     // get here, then we'll load a stale value and turn on the comparator.  But
  2369.     // the second bus reset will have disabled the async receiver, so we're OK.
  2370.     
  2371.     // UNLESS the second bus reset and the first PHY interrupt are combined and
  2372.     // we process them both at once.  In that case we'll do the bus reset first
  2373.     // and restore the async receiver, then load a stale value.  But another PHY
  2374.     // interrupt will come around within 150 microseconds and give us the true
  2375.     // value.  So there could be a window of about one cycle in which we might
  2376.     // send an ack for (and receive!) a packet that isn't ours.  Maybe that can
  2377.     // be prevented somehow.
  2378.     
  2379.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2380.  
  2381.     phyData = EndianSwap32Bit (pLynxRegs->phyControl);
  2382.     if (((phyData & kLynxPHY_REGRD_ADR) >> kLynxPHY_REGRD_ADRPhase) == 0)
  2383.     {
  2384.         phyData = (phyData & kLynxPHY_REGRD_DAT) >> kLynxPHY_REGRD_DATPhase;
  2385.         pLynxFWIMData->lastPhyReg0 = phyData;
  2386.         
  2387.         newNodeID = (phyData & kLynxPhyPhysicalID) >> kLynxPhyPhysicalIDPhase;
  2388.         busNodeID = pLynxRegs->busNumberNodeNumber;
  2389.         busNodeID &= ~EndianSwapImm32Bit (kLynxNODE_ID);
  2390.         busNodeID |= EndianSwap32Bit (newNodeID << kLynxNODE_IDPhase);
  2391.         pLynxRegs->busNumberNodeNumber = busNodeID;
  2392.         SynchronizeIO ();
  2393.         
  2394.         // If there hasn't been another reset by now, this will let us receive packets.
  2395.         // If there was another reset, the async receiver is disabled, so this does nothing.
  2396.         
  2397.         pLynxRegs->dmaComparator[kAsyncDMA].mask1 |= EndianSwapImm32Bit (kLynxEN_CH_COMPARE);
  2398.         SynchronizeIO ();
  2399.  
  2400.         // If there was a bus reset, and we were cycle master, and we aren't any more,
  2401.         // we need to turn off the cycle master ASAP in order to avoid PHY jams and to
  2402.         // avoid sending duplicate cycle starts.
  2403.  
  2404.         if ((phyData & kLynxPhyR) == 0)        // if not root
  2405.         {
  2406.             if (pLynxRegs->linkControl & EndianSwapImm32Bit (kLynxCYCMASTER))
  2407.             {
  2408.                 // zzz
  2409.                 // Although this should not conflict with someone setting CYCMASTER,
  2410.                 // It could conflict with other access to the LinkControl register.
  2411.                 // Those are rare, but they might re-enable cycle mastering, which is
  2412.                 // bad.  So this should be changed to a race-free method.
  2413.                 
  2414.                 // Disable cycle mastering.
  2415.                 LynxFWIMSetLinkControl
  2416.                     (pLynxFWIMData, EndianSwap32Bit (pLynxRegs->linkControl) & ~kLynxCYCMASTER);
  2417.             }
  2418.         }
  2419.     }
  2420. }
  2421.  
  2422.  
  2423. ////////////////////////////////////////////////////////////////////////////////
  2424. //
  2425. // LynxFWIMHandleMiscInterrupt
  2426. //
  2427. //   This proc handles miscellaneous interrupts.
  2428. //   This is only called #ifdef LynxFireBug
  2429. //  zzz no mechanism to prevent race condition in reporting.
  2430. //
  2431.  
  2432. static void LynxFWIMHandleMiscInterrupt(
  2433.     LynxFWIMDataPtr                pLynxFWIMData)
  2434. {
  2435.     OSStatus                    status = noErr;
  2436.  
  2437.     pLynxFWIMData->miscInterrupt = EndianSwap32Bit (
  2438.         pLynxFWIMData->pLynxRegisters->linkInterruptStatus &
  2439.         pLynxFWIMData->pLynxRegisters->linkInterruptEnable);
  2440.  
  2441.     // Schedule deferred task.
  2442.     if ((pLynxFWIMData->miscInterrupt) && !(pLynxFWIMData->miscInterruptDTScheduled))
  2443.     {
  2444.         status = FWScheduleDeferredTask (pLynxFWIMData->miscInterruptDeferredTaskID, nil);
  2445.  
  2446.         if (status == noErr)
  2447.             pLynxFWIMData->miscInterruptDTScheduled = true;
  2448.     }
  2449. }
  2450.  
  2451.  
  2452. ////////////////////////////////////////////////////////////////////////////////
  2453. //
  2454. // LynxFWIMResetBus
  2455. //
  2456. //   This routine initiates a bus reset.
  2457. //
  2458.  
  2459. static OSStatus LynxFWIMResetBus(
  2460.     FWIMCommandParamsPtr        pFWIMCommandParams,
  2461.     UInt32                        *pCommandAcceptance)
  2462. {
  2463.     LynxFWIMDataPtr                pLynxFWIMData;
  2464.     LynxRegistersPtr            pLynxRegs;
  2465.     UInt32                        phyReg;
  2466.     UInt32                        fifoMask;
  2467.     OSStatus                    status = noErr;
  2468.  
  2469.     // Get our internal data.
  2470.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2471.  
  2472. #ifdef LynxFireBug
  2473.     sprintf (fireBug, "LynxFWIM:  Bus reset from FSL");
  2474.     LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
  2475. #endif
  2476.  
  2477.     // Set pending command.
  2478.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  2479.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  2480.  
  2481.     // Get base address of Lynx registers.
  2482.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2483.  
  2484.     // For unknown reasons, sometimes the GRF will overflow and wedge, even though
  2485.     // all else is OK.  We never recover but we do send endless resets.  If the
  2486.     // following strict conditions are met (no DMA advance, no FIFO change) then
  2487.     // assume we are having this problem, and flush the GRF to recover.  This has
  2488.     // only been seen in non-revA parts.  This is different from a routine GRF
  2489.     // overflow, which results in a busyX and drains normally, invisible to us.
  2490.     
  2491.     // LynxFWIMProcessPacket sets lastARDMA to zero any time it receives a packet.
  2492.     // So accidental flushing should be impossible.  Flushing the GRF is very bad,
  2493.     // because it may contain a write request that we sent ack_complete to, and
  2494.     // that request will be lost.
  2495.     
  2496.     // This can be triggered by running the CCM receiver and the DV transmitter
  2497.     // simultaneously, and moving the mouse around.  This won't recover automatically,
  2498.     // but a bus reset will cause recovery.  [Could use a watchdog timer here...]
  2499.     
  2500.     fifoMask = EndianSwapImm32Bit (kLynxGRF_PTR | kLynxGRF_WAB);
  2501.         
  2502.     if ((pLynxFWIMData->lastARDMA == pLynxRegs->dmaChannel[kAsyncDMA].curPCLAddr) &&
  2503.         ((pLynxFWIMData->lastFIFOa & fifoMask) == (pLynxRegs->pciFifoPort & fifoMask)) &&
  2504.         ((pLynxFWIMData->lastFIFOb & fifoMask) == (pLynxRegs->linkFifoPort & fifoMask)))
  2505.     {
  2506. #ifdef LynxFireBug
  2507.         sprintf (fireBug, "LynxFWIM: ### Flushing GRF to recover from total FIFO jam");
  2508.         LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
  2509. #endif
  2510.         pLynxRegs->fifoControlEnableAndTest |= EndianSwapImm32Bit (kLynxGRF_FLUSH);
  2511.     }
  2512.  
  2513.     pLynxFWIMData->lastARDMA = pLynxRegs->dmaChannel[kAsyncDMA].curPCLAddr;
  2514.     pLynxFWIMData->lastFIFOa = pLynxRegs->pciFifoPort;
  2515.     pLynxFWIMData->lastFIFOb = pLynxRegs->linkFifoPort;
  2516.  
  2517.     // Issue the reset.
  2518.     phyReg = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhyIBRAddress);
  2519.     phyReg |= kLynxPhyIBR;
  2520.     LynxFWIMWritePhyRegister (pLynxRegs, kLynxPhyIBRAddress, phyReg);
  2521.  
  2522.     // Finish up command.
  2523.     pLynxFWIMData->pPendingFWIMCommand = nil;
  2524.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2525.  
  2526.     // Return command acceptance.
  2527.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2528.     //zzz well, it still works, but will it always?
  2529.     //zzz actually, when we switch to the dispatch table, each routine can return
  2530.     //zzz the appropriate acceptance, so don't worry about it for now.
  2531.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2532.  
  2533.     return (status);
  2534. }
  2535.  
  2536.  
  2537. ////////////////////////////////////////////////////////////////////////////////
  2538. //
  2539. // LynxFWIMSetContenderBit
  2540. //
  2541. //   This routine sets the contender bit in the self ID on the next bus reset.
  2542. //
  2543.  
  2544. static OSStatus LynxFWIMSetContenderBit(
  2545.     FWIMCommandParamsPtr        pFWIMCommandParams,
  2546.     UInt32                        *pCommandAcceptance)
  2547. {
  2548.     LynxFWIMDataPtr                pLynxFWIMData;
  2549.     LynxRegistersPtr            pLynxRegs;
  2550.     UInt32                        lynxReg;
  2551.     OSStatus                    status = noErr;
  2552.  
  2553.     // Get our internal data and register base address.
  2554.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2555.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2556.  
  2557.     // Set pending command.
  2558.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  2559.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  2560.  
  2561.     // Program the contender bit to be set on next reset.
  2562.     //zzz ought to have routine for setting gpios.
  2563.     lynxReg = EndianSwap32Bit (pLynxRegs->gpioControlA);
  2564.     lynxReg = (lynxReg & ~(kLynxGPIO_SRC0 | kLynxGPIO_POL_OUT0)) | kLynxGPIO_OUT_EN0;
  2565.     pLynxRegs->gpioControlA = EndianSwap32Bit (lynxReg);
  2566.     SynchronizeIO ();
  2567.     pLynxRegs->gpioData[1] = EndianSwapImm32Bit (1);
  2568.     SynchronizeIO ();
  2569.  
  2570.     // Finish up command.
  2571.     pLynxFWIMData->pPendingFWIMCommand = nil;
  2572.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2573.  
  2574.     // Return command acceptance.
  2575.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2576.     //zzz well, it still works, but will it always?
  2577.     //zzz actually, when we switch to the dispatch table, each routine can return
  2578.     //zzz the appropriate acceptance, so don't worry about it for now.
  2579.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2580.  
  2581.     return (status);
  2582. }
  2583.  
  2584.  
  2585. ////////////////////////////////////////////////////////////////////////////////
  2586. //
  2587. // LynxFWIMClearContenderBit
  2588. //
  2589. //   This routine clears the contender bit in the self ID on the next bus reset.
  2590. //
  2591.  
  2592. static OSStatus LynxFWIMClearContenderBit(
  2593.     FWIMCommandParamsPtr        pFWIMCommandParams,
  2594.     UInt32                        *pCommandAcceptance)
  2595. {
  2596.     LynxFWIMDataPtr                pLynxFWIMData;
  2597.     LynxRegistersPtr            pLynxRegs;
  2598.     UInt32                        lynxReg;
  2599.     OSStatus                    status = noErr;
  2600.  
  2601.     // Get our internal data and register base address.
  2602.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2603.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2604.  
  2605.     // Set pending command.
  2606.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  2607.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  2608.  
  2609.     // Program the contender bit to be clear on next reset.
  2610.     //zzz ought to have routine for setting gpios.
  2611.     lynxReg = EndianSwap32Bit (pLynxRegs->gpioControlA);
  2612.     lynxReg = (lynxReg & ~(kLynxGPIO_SRC0 | kLynxGPIO_POL_OUT0)) | kLynxGPIO_OUT_EN0;
  2613.     pLynxRegs->gpioControlA = EndianSwap32Bit (lynxReg);
  2614.     SynchronizeIO ();
  2615.     pLynxRegs->gpioData[1] = EndianSwapImm32Bit (0);
  2616.     SynchronizeIO ();
  2617.  
  2618.     // Finish up command.
  2619.     pLynxFWIMData->pPendingFWIMCommand = nil;
  2620.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2621.  
  2622.     // Return command acceptance.
  2623.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2624.     //zzz well, it still works, but will it always?
  2625.     //zzz actually, when we switch to the dispatch table, each routine can return
  2626.     //zzz the appropriate acceptance, so don't worry about it for now.
  2627.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2628.  
  2629.     return (status);
  2630. }
  2631.  
  2632.  
  2633. ////////////////////////////////////////////////////////////////////////////////
  2634. //
  2635. // LynxFWIMEnableCycleMaster
  2636. //
  2637. //   This routine enables cycle mastering.
  2638. //   Unlike the disable routine below, which is somewhat redundant, this routine
  2639. //   is the only place we set cycle master.  Setting cycle master is done only
  2640. //   after the IRM assigns a new cycle master, which is rare and isn't supposed
  2641. //   to be particularly fast. (ie, cycle loss is OK)
  2642. //
  2643. //   zzz should there be a mechanism to report failure, such as FSL asked us to
  2644. //   become cyclemaster, but by the time we got here, we aren't root anymore?
  2645. //
  2646.  
  2647. static OSStatus LynxFWIMEnableCycleMaster(
  2648.     FWIMCommandParamsPtr        pFWIMCommandParams,
  2649.     UInt32                        *pCommandAcceptance)
  2650. {
  2651.     LynxFWIMDataPtr                pLynxFWIMData;
  2652.     LynxRegistersPtr            pLynxRegs;
  2653.     OSStatus                    status = noErr;
  2654.  
  2655.     // Get our internal data and register base address.
  2656.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2657.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2658.  
  2659.     // Set pending command.
  2660.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  2661.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  2662.  
  2663.     // Enable cycle mastering if we're root.
  2664.     if (pLynxFWIMData->root)
  2665.     {
  2666.         // For safety, double-check that we're root:
  2667.         if (((volatile UInt8) (pLynxFWIMData->lastPhyReg0)) & kLynxPhyR)
  2668.         {
  2669.             LynxFWIMSetLinkControl
  2670.                 (pLynxFWIMData, EndianSwap32Bit (pLynxRegs->linkControl) | kLynxCYCMASTER);
  2671.  
  2672.             // And now, if we lost root, we may have screwed up linkControl.
  2673.             // This isn't perfect, but at least turn off the CYCMASTER
  2674.  
  2675.             if (!(((volatile UInt8) (pLynxFWIMData->lastPhyReg0)) & kLynxPhyR))
  2676.                 LynxFWIMSetLinkControl
  2677.                     (pLynxFWIMData, EndianSwap32Bit (pLynxRegs->linkControl) & ~kLynxCYCMASTER);
  2678.         }
  2679.     }
  2680.  
  2681.  
  2682.     // Finish up command.
  2683.     pLynxFWIMData->pPendingFWIMCommand = nil;
  2684.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2685.  
  2686.     // Return command acceptance.
  2687.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2688.     //zzz well, it still works, but will it always?
  2689.     //zzz actually, when we switch to the dispatch table, each routine can return
  2690.     //zzz the appropriate acceptance, so don't worry about it for now.
  2691.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2692.  
  2693.     return (status);
  2694. }
  2695.  
  2696.  
  2697. ////////////////////////////////////////////////////////////////////////////////
  2698. //
  2699. // LynxFWIMDisableCycleMaster
  2700. //
  2701. //   This routine disables cycle mastering.
  2702. //   Note, this is somewhat redundant, because we will have turned off cycle
  2703. //   mastering at primary interrupt level as soon as we lose root status.  The
  2704. //   only case in which this function would really do anything is if FSL wanted
  2705. //   to stop being the cycle master even though we are the root node.
  2706. //
  2707.  
  2708. static OSStatus LynxFWIMDisableCycleMaster(
  2709.     FWIMCommandParamsPtr        pFWIMCommandParams,
  2710.     UInt32                        *pCommandAcceptance)
  2711. {
  2712.     LynxFWIMDataPtr                pLynxFWIMData;
  2713.     LynxRegistersPtr            pLynxRegs;
  2714.     OSStatus                    status = noErr;
  2715.  
  2716.     // Get our internal data and register base address.
  2717.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2718.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2719.  
  2720.     // Set pending command.
  2721.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  2722.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  2723.  
  2724.     // Disable cycle mastering.
  2725.     LynxFWIMSetLinkControl
  2726.         (pLynxFWIMData, EndianSwap32Bit (pLynxRegs->linkControl) & ~kLynxCYCMASTER);
  2727.  
  2728.     // Finish up command.
  2729.     pLynxFWIMData->pPendingFWIMCommand = nil;
  2730.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2731.  
  2732.     // Return command acceptance.
  2733.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2734.     //zzz well, it still works, but will it always?
  2735.     //zzz actually, when we switch to the dispatch table, each routine can return
  2736.     //zzz the appropriate acceptance, so don't worry about it for now.
  2737.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2738.  
  2739.     return (status);
  2740. }
  2741.  
  2742.  
  2743. ////////////////////////////////////////////////////////////////////////////////
  2744. //
  2745. // LynxFWIMSetRootHoldoffBit
  2746. //
  2747. //   This routine sets the PHY root holdoff bit.
  2748. //
  2749.  
  2750. static OSStatus LynxFWIMSetRootHoldoffBit(
  2751.     FWIMCommandParamsPtr        pFWIMCommandParams,
  2752.     UInt32                        *pCommandAcceptance)
  2753. {
  2754.     LynxFWIMDataPtr                pLynxFWIMData;
  2755.     LynxRegistersPtr            pLynxRegs;
  2756.     UInt32                        phyReg;
  2757.     OSStatus                    status = noErr;
  2758.  
  2759.     // Get our internal data and register base address.
  2760.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2761.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2762.  
  2763.     // Set pending command.
  2764.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  2765.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  2766.  
  2767.     // Set the root holdoff bit in the PHY.
  2768.     phyReg = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhyRHBAddress);
  2769.     phyReg |= kLynxPhyRHB;
  2770.     LynxFWIMWritePhyRegister (pLynxRegs, kLynxPhyRHBAddress, phyReg);
  2771.  
  2772.     // Finish up command.
  2773.     pLynxFWIMData->pPendingFWIMCommand = nil;
  2774.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2775.  
  2776.     // Return command acceptance.
  2777.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2778.     //zzz well, it still works, but will it always?
  2779.     //zzz actually, when we switch to the dispatch table, each routine can return
  2780.     //zzz the appropriate acceptance, so don't worry about it for now.
  2781.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2782.  
  2783.     return (status);
  2784. }
  2785.  
  2786.  
  2787. ////////////////////////////////////////////////////////////////////////////////
  2788. //
  2789. // LynxFWIMClearRootHoldoffBit
  2790. //
  2791. //   This routine clears the PHY root holdoff bit.
  2792. //
  2793.  
  2794. static OSStatus LynxFWIMClearRootHoldoffBit(
  2795.     FWIMCommandParamsPtr        pFWIMCommandParams,
  2796.     UInt32                        *pCommandAcceptance)
  2797. {
  2798.     LynxFWIMDataPtr                pLynxFWIMData;
  2799.     LynxRegistersPtr            pLynxRegs;
  2800.     UInt32                        phyReg;
  2801.     OSStatus                    status = noErr;
  2802.  
  2803.     // Get our internal data and register base address.
  2804.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2805.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  2806.  
  2807.     // Set pending command.
  2808.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMCommandParams;
  2809.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  2810.  
  2811.     // Clear the root holdoff bit in the PHY.
  2812.     phyReg = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhyRHBAddress);
  2813.     phyReg &= ~kLynxPhyRHB;
  2814.     LynxFWIMWritePhyRegister (pLynxRegs, kLynxPhyRHBAddress, phyReg);
  2815.  
  2816.     // Finish up command.
  2817.     pLynxFWIMData->pPendingFWIMCommand = nil;
  2818.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2819.  
  2820.     // Return command acceptance.
  2821.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2822.     //zzz well, it still works, but will it always?
  2823.     //zzz actually, when we switch to the dispatch table, each routine can return
  2824.     //zzz the appropriate acceptance, so don't worry about it for now.
  2825.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2826.  
  2827.     return (status);
  2828. }
  2829.  
  2830.  
  2831. ////////////////////////////////////////////////////////////////////////////////
  2832. //
  2833. // LynxFWIMGetUniqueID
  2834. //
  2835. //   This routine returns the local unique ID.
  2836. //
  2837.  
  2838. static OSStatus    LynxFWIMGetUniqueID(
  2839.     FWIMGetUniqueIDParamsPtr    pFWIMGetUniqueIDParams,
  2840.     UInt32                        *pCommandAcceptance)
  2841. {
  2842.     LynxFWIMDataPtr                pLynxFWIMData;
  2843.     FWIMCommandParamsPtr        pFWIMCommandParams;
  2844.     OSStatus                    status = noErr;
  2845.     
  2846.     // Get our internal data.
  2847.     pFWIMCommandParams = &(pFWIMGetUniqueIDParams->fwimCommandParams);
  2848.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2849.  
  2850.     if (pLynxFWIMData->eepromValid)
  2851.     {
  2852.         pFWIMGetUniqueIDParams->uniqueID.hi = pLynxFWIMData->eepromInfo.busInfoBlock[2];
  2853.         pFWIMGetUniqueIDParams->uniqueID.lo = pLynxFWIMData->eepromInfo.busInfoBlock[3];
  2854.     }
  2855.     else
  2856.     {
  2857.         //zzz Fake it
  2858.         pFWIMGetUniqueIDParams->uniqueID.hi = 'lynx';
  2859.         pFWIMGetUniqueIDParams->uniqueID.lo = (UInt32) pLynxFWIMData;
  2860.     }
  2861.     
  2862. //    sprintf (debugStr, "LynxFWIMGetUniqueID : Node Vendor ID %06lx   Chip ID %02lx%08lx",
  2863. //             (long) pFWIMGetUniqueIDParams->uniqueID.hi >> 8,
  2864. //             (long) pFWIMGetUniqueIDParams->uniqueID.hi & 0xff,
  2865. //             (long) pFWIMGetUniqueIDParams->uniqueID.lo);
  2866. //    FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  2867.     
  2868.     // Finish up command.
  2869.     pLynxFWIMData->pPendingFWIMCommand = nil;
  2870.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2871.  
  2872.     // Return command acceptance.
  2873.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2874.     //zzz well, it still works, but will it always?
  2875.     //zzz actually, when we switch to the dispatch table, each routine can return
  2876.     //zzz the appropriate acceptance, so don't worry about it for now.
  2877.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2878.  
  2879.     return (status);
  2880. }
  2881.  
  2882.  
  2883. ////////////////////////////////////////////////////////////////////////////////
  2884. //
  2885. // LynxFWIMSendLinkOnPacket
  2886. //
  2887. //   This proc sends the given link on packet.
  2888. //
  2889.  
  2890. static OSStatus    LynxFWIMSendLinkOnPacket(
  2891.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  2892.     UInt32                        *pCommandAcceptance)
  2893. {
  2894.     LynxFWIMDataPtr                pLynxFWIMData;
  2895.     FWIMCommandParamsPtr        pFWIMCommandParams;
  2896.     UInt32                        linkOnData;
  2897.     OSStatus                    status = noErr;
  2898.     
  2899.     // Get our internal data.
  2900.     pFWIMCommandParams = &(pFWIMSendPhyPacketParams->fwimCommandParams);
  2901.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2902.  
  2903.     // Set pending command.
  2904.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMSendPhyPacketParams;
  2905.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  2906.  
  2907.     // Check if generation is up to date.
  2908.     if ((!(pLynxFWIMData->generationValid)) ||
  2909.         (pFWIMSendPhyPacketParams->generation != pLynxFWIMData->generation))
  2910.     {
  2911.         status = busReconfiguredErr;
  2912.     }
  2913.  
  2914.     // Set up link on data.
  2915.     if (status == noErr)
  2916.     {
  2917.         linkOnData = *((UInt32 *) (pFWIMSendPhyPacketParams->buffer));
  2918.         linkOnData &= ~kFWPhyPacketID;
  2919.         linkOnData |= kFWLinkOnPacketID << kFWPhyPacketIDPhase;
  2920.     }
  2921.     
  2922.     // Send packet.
  2923.     if (status == noErr)
  2924.     {
  2925.         LynxFWIMWriteATF (pLynxFWIMData, kLynxDMA_UNFORMATTED_XMT, kFWSpeed100MBit, 2,
  2926.                           linkOnData, ~linkOnData, 0, 0, 0, 0);
  2927.     }
  2928.  
  2929.     // Finish up command.
  2930.     pLynxFWIMData->pPendingFWIMCommand = nil;
  2931.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2932.  
  2933.     // Return command acceptance.
  2934.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2935.     //zzz well, it still works, but will it always?
  2936.     //zzz actually, when we switch to the dispatch table, each routine can return
  2937.     //zzz the appropriate acceptance, so don't worry about it for now.
  2938.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  2939.  
  2940.     return (status);
  2941. }
  2942.  
  2943.  
  2944. ////////////////////////////////////////////////////////////////////////////////
  2945. //
  2946. // LynxFWIMSendPhyConfigurationPacket
  2947. //
  2948. //   This proc sends the given Phy configuration packet.
  2949. //
  2950.  
  2951. static OSStatus    LynxFWIMSendPhyConfigurationPacket(
  2952.     FWIMSendPhyPacketParamsPtr    pFWIMSendPhyPacketParams,
  2953.     UInt32                        *pCommandAcceptance)
  2954. {
  2955.     LynxFWIMDataPtr                pLynxFWIMData;
  2956.     FWIMCommandParamsPtr        pFWIMCommandParams;
  2957.     UInt32                        configurationData;
  2958.     OSStatus                    status = noErr;
  2959.     
  2960.     // Get our internal data.
  2961.     pFWIMCommandParams = &(pFWIMSendPhyPacketParams->fwimCommandParams);
  2962.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  2963.  
  2964.     // Set pending command.
  2965.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMSendPhyPacketParams;
  2966.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  2967.  
  2968.     // Check if generation is up to date.
  2969.     if ((!(pLynxFWIMData->generationValid)) ||
  2970.         (pFWIMSendPhyPacketParams->generation != pLynxFWIMData->generation))
  2971.     {
  2972.         status = busReconfiguredErr;
  2973.     }
  2974.  
  2975.     // Set up phy configuration data.
  2976.     if (status == noErr)
  2977.     {
  2978.         configurationData = *((UInt32 *) (pFWIMSendPhyPacketParams->buffer));
  2979.         configurationData &= ~kFWPhyPacketID;
  2980.         configurationData |= kFWConfigurationPacketID << kFWPhyPacketIDPhase;
  2981.     }
  2982.     
  2983.     // Send packet.
  2984.     if (status == noErr)
  2985.     {
  2986.         LynxFWIMWriteATF (pLynxFWIMData, kLynxDMA_UNFORMATTED_XMT, kFWSpeed100MBit, 2,
  2987.                           configurationData, ~configurationData, 0, 0, 0, 0);
  2988.     }
  2989.  
  2990.     // Finish up command.
  2991.     pLynxFWIMData->pPendingFWIMCommand = nil;
  2992.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  2993.  
  2994.     // Return command acceptance.
  2995.     //zzz what if we call FWIMCommandIsComplete before returning this???
  2996.     //zzz well, it still works, but will it always?
  2997.     //zzz actually, when we switch to the dispatch table, each routine can return
  2998.     //zzz the appropriate acceptance, so don't worry about it for now.
  2999.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  3000.  
  3001.     return (status);
  3002. }
  3003.  
  3004.  
  3005. ////////////////////////////////////////////////////////////////////////////////
  3006. //
  3007. // LynxFWIMWritePhyRegister
  3008. //
  3009. //   This proc writes data to the specified phy register.
  3010. //
  3011.  
  3012. static void    LynxFWIMWritePhyRegister(
  3013.     LynxRegistersPtr            pLynxRegs,
  3014.     UInt8                        regAddress,
  3015.     UInt8                        regData)
  3016. {
  3017.     UInt32                        phyChipAccess;
  3018.     UInt32                        patience;
  3019.  
  3020. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMWritePhyRegister");
  3021.  
  3022.     if (pLynxRegs->phyControl & EndianSwapImm32Bit (kLynxWRPHY))
  3023.         FWDebugStr ((ConstStr255Param) "\pLynxFWIMWritePhyRegister - write bit already set!!!");
  3024.  
  3025.     // Set up phyChipAccess to write phy.
  3026.     // Set the write bit, the register address, and data.
  3027.     phyChipAccess = kLynxWRPHY;
  3028.     phyChipAccess |= (regAddress << kLynxPHY_REG_ADRPhase) & kLynxPHY_REG_ADR;
  3029.     phyChipAccess |= (regData << kLynxPHY_REG_DATPhase) & kLynxPHY_REG_DAT;
  3030.     pLynxRegs->phyControl = EndianSwap32Bit (phyChipAccess);
  3031.     SynchronizeIO ();
  3032.  
  3033.     patience = 100000;
  3034.     while (patience-- && (pLynxRegs->phyControl & EndianSwapImm32Bit (kLynxWRPHY)))
  3035.     {
  3036.         SynchronizeIO();
  3037.         if (!patience)
  3038.             FWDebugStr ((ConstStr255Param) "\pLynxFWIMWritePhyRegister:  waited too long");
  3039.     }
  3040. }
  3041.  
  3042.  
  3043. ////////////////////////////////////////////////////////////////////////////////
  3044. //
  3045. // LynxFWIMReadPhyRegister
  3046. //
  3047. //   This proc reads data from the specified phy register.
  3048. //   This has the side effect of triggering a PHY received interrupt,
  3049. //   which should be harmless.
  3050. // zzz Still need to make the timeouts use real time, not CPU clocks.
  3051. //
  3052.  
  3053. static UInt8    LynxFWIMReadPhyRegister(
  3054.     LynxRegistersPtr            pLynxRegs,
  3055.     UInt8                        regAddress)
  3056. {
  3057.     UInt32                        phyChipAccess,
  3058.                                 phyChipAccessRead;
  3059.     UInt8                        returnedAddress;
  3060.     UInt8                        regData;
  3061.     UInt32                        patience;
  3062.  
  3063. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadPhyRegister");
  3064.  
  3065.     // Set up phyChipAccess register to read phy.
  3066.     // Set read bit, register address, and set returned read address to an
  3067.     // invalid phy address, so we can tell when it changes.
  3068.     phyChipAccessRead = kLynxRDPHY;
  3069.     phyChipAccessRead |= (regAddress << kLynxPHY_REG_ADRPhase) & kLynxPHY_REG_ADR;
  3070.     phyChipAccessRead |= (kLynxPhyInvalidAddress << kLynxPHY_REGRD_ADRPhase) &
  3071.                          kLynxPHY_REGRD_ADR;
  3072.     pLynxRegs->phyControl = EndianSwap32Bit (phyChipAccessRead);
  3073.     SynchronizeIO ();
  3074.  
  3075.     // Wait for the desired return read address.
  3076.     // Tests show that this typically takes 10 microseconds,
  3077.     // though I have seen it take up to 330 microseconds.
  3078.     // Of course, if the card has wedged, this will take forever.
  3079.     do
  3080.     {
  3081.         // Wait for read to be sent.
  3082.         patience = 2000;
  3083.         while (patience-- && (pLynxRegs->phyControl & EndianSwapImm32Bit (kLynxRDPHY)))
  3084.         {
  3085.             UInt32 wait = 2000;
  3086.             while (wait--) SynchronizeIO();
  3087.             if (!patience)
  3088.             {
  3089.                 if (NoPhyReset)
  3090.                 {
  3091.                     FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadPhyRegister - WAITED TOO LONG, but cannot reset right now");
  3092.                     return 0;
  3093.                 }
  3094.                 else
  3095.                 {
  3096.                     FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadPhyRegister - WAITED TOO LONG, full card reset");
  3097.                     LynxFWIMFullReset();
  3098.                 }
  3099.             }
  3100.         }
  3101.  
  3102.         phyChipAccess = EndianSwap32Bit (pLynxRegs->phyControl);
  3103.  
  3104.         // Read returned address.
  3105.         returnedAddress = (phyChipAccess & kLynxPHY_REGRD_ADR) >>
  3106.                           kLynxPHY_REGRD_ADRPhase;
  3107.  
  3108.         // If RDPHY still set, make sure we don't accept the value
  3109.         if (phyChipAccess & kLynxRDPHY)
  3110.             returnedAddress = 0xfff;
  3111.             
  3112.         // If returned address is not what we we're looking for and not what
  3113.         // we set it to, start another read.
  3114.         if ((returnedAddress != regAddress) &&
  3115.             (returnedAddress != kLynxPhyInvalidAddress))
  3116.         {
  3117.             pLynxRegs->phyControl = EndianSwap32Bit (phyChipAccessRead);
  3118.             SynchronizeIO ();
  3119.         }
  3120.     } while (returnedAddress != regAddress);
  3121.  
  3122.     // Extract and return phy register contents.
  3123.     regData = (phyChipAccess & kLynxPHY_REGRD_DAT) >>
  3124.               kLynxPHY_REGRD_DATPhase;
  3125.     return regData;
  3126. }
  3127.  
  3128.  
  3129. ////////////////////////////////////////////////////////////////////////////////
  3130. //
  3131. // LynxFWIMPrepareAsyncDMA
  3132. //
  3133. //   This proc perpares PCLs for async receive and primes the DMA.
  3134. //
  3135.  
  3136. static void LynxFWIMPrepareAsyncDMA(
  3137.     LynxFWIMDataPtr                pLynxFWIMData,
  3138.     UInt32                        channel)
  3139. {
  3140.     // Create the async receive PCL program.
  3141.     LynxFWIMCreateAsyncRxPCLProgram (pLynxFWIMData);
  3142.  
  3143.     // Start async receive PCL program.
  3144.     LynxFWIMStartAsyncRxPCLProgram
  3145.         (pLynxFWIMData, &(pLynxFWIMData->asyncPCL[kAsyncRxFirstPacketPCL]));
  3146. }
  3147.  
  3148.  
  3149. ////////////////////////////////////////////////////////////////////////////////
  3150. //
  3151. // LynxFWIMAddAsyncRxPCL
  3152. //
  3153. //   This proc adds a PCL to the active async receive PCL list.
  3154. //
  3155.  
  3156. static void LynxFWIMAddAsyncRxPCL(
  3157.     LynxPCLPtr                    pPCL)
  3158. {
  3159.     LynxFWIMDataPtr                pLynxFWIMData;
  3160.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData,
  3161.                                 pPrevLynxAsyncRxPCLData,
  3162.                                 pOverflowLynxAsyncRxPCLData;
  3163.     LynxPCLPtr                    pPrevPCL,
  3164.                                 pOverflowPCL;
  3165.  
  3166.     // Get PCL data and Lynx FWIM data for PCL to add.
  3167.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  3168.     pLynxFWIMData = pLynxAsyncRxPCLData->pLynxFWIMData;
  3169.  
  3170.     // Get PCL and PCL data for overflow handling.
  3171.     pOverflowPCL = pLynxFWIMData->asyncRxOverflowPCLSegment;
  3172.     pOverflowLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pOverflowPCL->refCon;
  3173.  
  3174.     // Link new PCL to overflow handler and invalidate new PCL's status.
  3175.     pPCL->nextPCL =
  3176.         (UInt32 *) EndianSwap32Bit ((UInt32) pOverflowLynxAsyncRxPCLData->pPCLPhysical);
  3177.     pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
  3178.     pLynxAsyncRxPCLData->pNextPCL = nil;
  3179.  
  3180.     // Get last async receive PCL.
  3181.     pPrevPCL = pLynxFWIMData->pLastAsyncPCL;
  3182.  
  3183.     // Link new PCL to last one.
  3184.     if ((pPrevPCL != nil) && (pLynxFWIMData->pNextAsyncPCL != nil))
  3185.     {
  3186.         pPrevPCL->nextPCL =
  3187.             (UInt32 *) EndianSwap32Bit ((UInt32) pLynxAsyncRxPCLData->pPCLPhysical);
  3188.         pPrevLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPrevPCL->refCon;
  3189.         pPrevLynxAsyncRxPCLData->pNextPCL = pPCL;
  3190.     }
  3191.     else
  3192.     {
  3193.         pLynxFWIMData->pNextAsyncPCL = pPCL;
  3194.     }
  3195.  
  3196.     // Check for overflow.
  3197.     if (pLynxFWIMData->asyncRxOverflowFlag)
  3198.     {
  3199.         // Restart async receive PCL program at new PCL if it's still unused.
  3200.         if (pPCL->status == EndianSwapImm32Bit (kLynxInvalidStatus))
  3201.             LynxFWIMStartAsyncRxPCLProgram (pLynxFWIMData, pPCL);
  3202.     }
  3203.  
  3204.     // New PCL is now last.
  3205.     pLynxFWIMData->pLastAsyncPCL = pPCL;
  3206. }
  3207.  
  3208.  
  3209. ////////////////////////////////////////////////////////////////////////////////
  3210. //
  3211. // LynxFWIMCreateAsyncRxPCLProgram
  3212. //
  3213. //   This proc creates the async receive PCL program.
  3214. //
  3215.  
  3216. static void LynxFWIMCreateAsyncRxPCLProgram(
  3217.     LynxFWIMDataPtr                pLynxFWIMData)
  3218. {
  3219.     LynxFWIMDataPtr                pPhysLynxFWIMData;
  3220.     LynxRegistersPtr            pLynxRegs;
  3221.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  3222.     LynxPCLPtr                    pPCL;
  3223.     UInt32                        pclNum,
  3224.                                 packetNum;
  3225.     
  3226.     // Get pointer to link registers and physical pointer to FWIM data.
  3227.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3228.     pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
  3229.  
  3230.     // Create dummy PCL for starting.
  3231.     LynxFWIMCreateAsyncRxDummyPCL (pLynxFWIMData);
  3232.  
  3233.     // Create overflow segment.
  3234.     LynxFWIMCreateAsyncRxOverflowPCLSegment (pLynxFWIMData);
  3235.  
  3236.     // Create packet PCLs.
  3237.     for (pclNum = kAsyncRxFirstPacketPCL, packetNum = 0;
  3238.          pclNum <= kAsyncRxLastPacketPCL;
  3239.          pclNum++, packetNum++)
  3240.     {
  3241.         // Get pointer to PCL.
  3242.         pPCL = &(pLynxFWIMData->asyncPCL[pclNum]);
  3243.  
  3244.         // Add PCL data record.
  3245.         pLynxAsyncRxPCLData = &(pLynxFWIMData->lynxAsyncRxPCLDataList[pclNum]);
  3246.         pLynxAsyncRxPCLData->pLynxFWIMData = pLynxFWIMData;
  3247.         pLynxAsyncRxPCLData->pPCLPhysical =
  3248.             pLynxFWIMData->asyncPCLPhys + (pclNum * sizeof (LynxPCL));
  3249.         pLynxAsyncRxPCLData->packetBuffer = pLynxFWIMData->asyncBuf[packetNum];
  3250.         pPCL->refCon = (UInt32) pLynxAsyncRxPCLData;
  3251.  
  3252.         // Initialize PCL header.
  3253.         pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  3254.  
  3255.         // Set up PCL buffers.
  3256.         pPCL->buffer[0].control =
  3257.             EndianSwapImm32Bit ((kLynxDMA_RCV << kLynxDMA_CMDPhase) |
  3258.                                 kLynxDMA_LAST_BUF |
  3259.                                 kPacketBufferSize |
  3260.                                 kLynxDMA_INT);
  3261.         pPCL->buffer[0].address =
  3262.             (UInt32 *) EndianSwap32Bit ((UInt32) pLynxFWIMData->asyncBufPhys[packetNum]);
  3263.  
  3264.         // Add PCL to program.
  3265.         LynxFWIMAddAsyncRxPCL (pPCL);
  3266.     }
  3267. }
  3268.  
  3269.  
  3270. ////////////////////////////////////////////////////////////////////////////////
  3271. //
  3272. // LynxFWIMCreateAsyncRxDummyPCL
  3273. //
  3274. //   This proc creates a dummy PCL for starting the async receive PCL program.
  3275. //
  3276.  
  3277. static void LynxFWIMCreateAsyncRxDummyPCL(
  3278.     LynxFWIMDataPtr                pLynxFWIMData)
  3279. {
  3280.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  3281.     LynxPCLPtr                    pPCL;
  3282.  
  3283.     // Just fill in the basics.
  3284.     pPCL = &(pLynxFWIMData->asyncPCL[kAsyncRxDummyPCL]);
  3285.     pLynxAsyncRxPCLData = &(pLynxFWIMData->lynxAsyncRxPCLDataList[kAsyncRxDummyPCL]);
  3286.     pLynxAsyncRxPCLData->pLynxFWIMData = pLynxFWIMData;
  3287.     pLynxAsyncRxPCLData->pPCLPhysical =
  3288.         pLynxFWIMData->asyncPCLPhys + (kAsyncRxDummyPCL * sizeof (LynxPCL));
  3289.     pPCL->refCon = (UInt32) pLynxAsyncRxPCLData;
  3290. }
  3291.  
  3292.  
  3293. ////////////////////////////////////////////////////////////////////////////////
  3294. //
  3295. // LynxFWIMCreateAsyncRxOverflowPCLSegment
  3296. //
  3297. //   This proc creates the async receive overflow PCL segment.
  3298. //zzz what should happen if we get to end of list?
  3299. //
  3300.  
  3301. static void LynxFWIMCreateAsyncRxOverflowPCLSegment(
  3302.     LynxFWIMDataPtr                pLynxFWIMData)
  3303. {
  3304.     LynxFWIMDataPtr                pPhysLynxFWIMData;
  3305.     LynxRegistersPtr            pLynxRegs;
  3306.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  3307.     LynxPCLPtr                    pPCL;
  3308.  
  3309.     // This PCL goes at the end of the async receive PCL program.  If we run out
  3310.     // of async receive PCLs, we want to do a controlled shutdown so that we send
  3311.     // the right ack code on any future packets (ack_busyX).  So this PCL sets a
  3312.     // bit that causes ack_busyX for all packets.  That way, packets don't pile up
  3313.     // in the GRF.
  3314.     
  3315.     // At present, some packets could be in the FIFO by the time we set the busyX
  3316.     // bit.  Those packets will linger there until we recover, and they will
  3317.     // block any incoming isoch packets.  That's not good.  We should add more PCLs
  3318.     // after this one that will drain the FIFO (but not bitbucket the packets).
  3319.  
  3320.     // By leaving the comparator enabled, we send busyX, which hopefully will buy
  3321.     // us some time.  Here's a rundown of how Lynx determines ack values:
  3322.     
  3323.     // After a bus reset, the async receiver is disabled.  We don't ack any packet.
  3324.     // If the Async receiver is enabled, then each packet is checked against the
  3325.     // nodeID set in register 0xF00.  Packets for other nodes are ignored.
  3326.     //
  3327.     // If the incoming packet matches our node ID, then...
  3328.     //   If there is no comparator enabled that matches the packet, send no ack.
  3329.     //      [A Lynx at the other end will see a Link Timeout]
  3330.     //   If there is a comparator enabled that matches the packet...
  3331.     //      If the busy bit in register 0xF04 is set, send ack_busyX
  3332.     //      If not, try to receive the packet...
  3333.     //        If there is a FIFO overflow, send ack_busyX
  3334.     //        If there is a CRC error, send ack_dataErr (probably.  Very rare)
  3335.     //        If we're still OK...
  3336.     //          If it's a broadcast packet, send no ack.
  3337.     //          If it's a write and the comparator has WRITE_REQ_ACK_SEL, send ack_complete
  3338.     //          Otherwise send ack_pending
  3339.  
  3340.     // Note that we do set WRITE_REQ_ACK_SEL so that we won't have to send a write
  3341.     // response later.  This is why any packets left over in the FIFO after we run
  3342.     // out of PCLs must still be received - if we sent ack_complete, and they are
  3343.     // write requests, we must not throw them away.  We already said we took care of them.
  3344.     
  3345.     // Get pointer to link registers and physical pointer to FWIM data.
  3346.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3347.     pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
  3348.  
  3349.     // Set up PCL to busy incoming packets.
  3350.     //zzz should be a little cleaner
  3351.     pPCL = &(pLynxFWIMData->asyncPCL[kAsyncRxOverrunPCL]);
  3352.     pPCL->nextPCL = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  3353.     pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  3354.     pLynxAsyncRxPCLData = &(pLynxFWIMData->lynxAsyncRxPCLDataList[kAsyncRxOverrunPCL]);
  3355.     pLynxAsyncRxPCLData->pLynxFWIMData = pLynxFWIMData;
  3356.     pLynxAsyncRxPCLData->pPCLPhysical =
  3357.             pLynxFWIMData->asyncPCLPhys + (kAsyncRxOverrunPCL * sizeof (LynxPCL));
  3358.     pPCL->refCon = (UInt32) pLynxAsyncRxPCLData;
  3359.     pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
  3360.     pPCL->remaining = EndianSwapImm32Bit (0);
  3361.     pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
  3362.  
  3363.     // If we leave the comparator enabled, but set this busy bit, then we'll
  3364.     // send ack_busyX to all inbound async packets.  If we turn the comparator
  3365.     // off too (like we used to) then we won't ack packets at all, which may
  3366.     // confuse the sender.
  3367.     
  3368.     // Set link to busy all async packets.
  3369.     pPCL->buffer[0].control = EndianSwapImm32Bit (kLynxDMA_LOAD << kLynxDMA_CMDPhase);
  3370.     pPCL->buffer[0].address = (UInt32 *)
  3371.         EndianSwap32Bit ((UInt32) &(pPhysLynxFWIMData->asyncRxOverflowSetLinkControl));
  3372.     pPCL->buffer[1].control =
  3373.         EndianSwapImm32Bit (kLynxDMA_STORE_QUAD << kLynxDMA_CMDPhase);
  3374.     pPCL->buffer[1].address =
  3375.         (UInt32 *) EndianSwap32Bit ((UInt32) &(pLynxRegs->linkControl));
  3376.  
  3377.     // Historical note - we used to turn off the comparator.  That prevents the
  3378.     // bit for sending ack_busyX from working and causes us to send no ack.  So
  3379.     // we don't do that anymore.
  3380.     
  3381.     // Set overflow flag so software knows this happened
  3382.     pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
  3383.     pPCL->buffer[2].control =
  3384.         EndianSwapImm32Bit ((kLynxDMA_STORE1 << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
  3385.     pPCL->buffer[2].address =
  3386.         (UInt32 *) EndianSwap32Bit ((UInt32) &(pPhysLynxFWIMData->asyncRxOverflowFlag));
  3387.  
  3388.     // Set PCL segment in FWIM data.
  3389.     pLynxFWIMData->asyncRxOverflowPCLSegment = pPCL;
  3390. }
  3391.  
  3392.  
  3393. ////////////////////////////////////////////////////////////////////////////////
  3394. //
  3395. // LynxFWIMStartAsyncRxPCLProgram
  3396. //
  3397. //   This proc starts the async receive PCL program.
  3398. //
  3399.  
  3400. static void LynxFWIMStartAsyncRxPCLProgram(
  3401.     LynxFWIMDataPtr                pLynxFWIMData,
  3402.     LynxPCLPtr                    pStartPCL)
  3403. {
  3404.     LynxRegistersPtr            pLynxRegs;
  3405.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData,
  3406.                                 pStartLynxAsyncRxPCLData;
  3407.     LynxPCLPtr                    pPCL;
  3408.     Boolean                        asyncRxReady = false;
  3409.  
  3410.     // Get pointer to link registers and start PCL's data.
  3411.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3412.  
  3413.     // Check for overflow.
  3414.     if (pLynxFWIMData->asyncRxOverflowFlag)
  3415.     {
  3416.         // Check if we've started priming.
  3417.         if (pLynxFWIMData->numAsyncRxPCLsPrimed == 0)
  3418.         {
  3419.             pLynxFWIMData->pStartAsyncRxPCL = pStartPCL;
  3420.             pLynxFWIMData->numAsyncRxPCLsPrimed = 1;
  3421.         }
  3422.         else
  3423.         {
  3424.             pLynxFWIMData->numAsyncRxPCLsPrimed++;
  3425.         }
  3426.  
  3427.         // Check if we've primed enough receive PCLs.
  3428.         if (pLynxFWIMData->numAsyncRxPCLsPrimed >= kLynxNumAsyncRxPCLsToPrime)
  3429.         {
  3430.             pLynxFWIMData->asyncRxOverflowFlag = 0;
  3431.             pLynxFWIMData->numAsyncRxPCLsPrimed = 0;
  3432.             asyncRxReady = true;
  3433.         }
  3434.     }
  3435.     else
  3436.     {
  3437.         // We're ready to receive.
  3438.         pLynxFWIMData->pStartAsyncRxPCL = pStartPCL;
  3439.         asyncRxReady = true;
  3440.     }
  3441.  
  3442.     if (asyncRxReady)
  3443.     {
  3444.         // Quiet the DMA channel.
  3445.         pLynxRegs->dmaChannel[kAsyncDMA].control = EndianSwapImm32Bit (0);
  3446.         SynchronizeIO();
  3447.     
  3448.         // Start the PCL program at the given PCL.
  3449.         pPCL = &(pLynxFWIMData->asyncPCL[kAsyncRxDummyPCL]);
  3450.         pStartLynxAsyncRxPCLData =
  3451.             (LynxAsyncRxPCLDataPtr) pLynxFWIMData->pStartAsyncRxPCL->refCon;
  3452.         pPCL->nextPCL =
  3453.             (UInt32 *) EndianSwap32Bit ((UInt32) pStartLynxAsyncRxPCLData->pPCLPhysical);
  3454.         pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  3455.         pLynxRegs->dmaChannel[kAsyncDMA].curPCLAddr =
  3456.             EndianSwap32Bit ((UInt32) pLynxAsyncRxPCLData->pPCLPhysical);
  3457.         SynchronizeIO();
  3458.     
  3459.         // Note, not clear that the ready register really matters here
  3460.         
  3461.         // Enable the DMA.
  3462.         pLynxRegs->dmaChannel[kAsyncDMA].ready = EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
  3463.         SynchronizeIO();
  3464.         pLynxRegs->dmaChannel[kAsyncDMA].control =
  3465.             EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  3466.         SynchronizeIO();
  3467.     
  3468.         // Really only need to do this once
  3469.         
  3470.         // Enable comparator.
  3471.         pLynxRegs->dmaComparator[kAsyncDMA].mask0 =
  3472.             EndianSwapImm32Bit (kLynxAsynctCodeNormal << kLynxCMP0_FIELD3_MASKPhase);
  3473.         LynxFWIMSetAsyncRxComparatorMask1
  3474.             (pLynxFWIMData,
  3475.              kLynxRCV_SELF_ID_EN |
  3476.              kLynkDEST_ID_SEL_BusNode |
  3477.              kLynxEN_CH_COMPARE |
  3478.              kLynxWRITE_REQ_ACK_SEL);
  3479.     
  3480.         // Clear busy flag in linkControl.
  3481.         LynxFWIMSetLinkControl
  3482.             (pLynxFWIMData, EndianSwap32Bit (pLynxRegs->linkControl) & ~kLynxBUSY_CNTRL);
  3483.     }
  3484. }
  3485.  
  3486.  
  3487. ////////////////////////////////////////////////////////////////////////////////
  3488. //
  3489. // LynxFWIMAddAsyncTxPCL
  3490. //
  3491. //   This proc adds a PCL to the active async transmit PCL list.
  3492. //
  3493.  
  3494. static void LynxFWIMAddAsyncTxPCL(
  3495.     LynxPCLPtr                    pPCL)
  3496. {
  3497.     LynxFWIMDataPtr                pLynxFWIMData;
  3498.     LynxAsyncTxPCLDataPtr        pLynxAsyncTxPCLData,
  3499.                                 pPrevLynxAsyncTxPCLData,
  3500.                                 pDoneLynxAsyncRxPCLData;
  3501.     LynxPCLPtr                    pPrevPCL,
  3502.                                 pDonePCL;
  3503.  
  3504.     // Get PCL data and Lynx FWIM data for PCL to add.
  3505.     pLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pPCL->refCon;
  3506.     pLynxFWIMData = pLynxAsyncTxPCLData->pLynxFWIMData;
  3507.  
  3508.     // Get PCL and PCL data for done handling.
  3509.     pDonePCL = pLynxFWIMData->asyncTxDonePCLSegment;
  3510.     pDoneLynxAsyncRxPCLData = (LynxAsyncTxPCLDataPtr) pDonePCL->refCon;
  3511.  
  3512.     // Link new PCL to done handler and invalidate new PCL's status.
  3513.     pPCL->nextPCL =
  3514.         (UInt32 *) EndianSwap32Bit ((UInt32) pDoneLynxAsyncRxPCLData->pPCLPhysical);
  3515.     pPCL->nextPCLAlt =
  3516.         (UInt32 *) EndianSwap32Bit ((UInt32) pDoneLynxAsyncRxPCLData->pPCLPhysical);
  3517.     pLynxAsyncTxPCLData->pNextPCL = nil;
  3518.     pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
  3519.  
  3520.     // Get last async transmit PCL.
  3521.     pPrevPCL = pLynxFWIMData->pLastAsyncTxPCL;
  3522.  
  3523.     // Link new PCL to last one.
  3524.     if ((pPrevPCL != nil) && (pLynxFWIMData->pNextAsyncTxPCL != nil))
  3525.     {
  3526.         pPrevPCL->nextPCL =
  3527.             (UInt32 *) EndianSwap32Bit ((UInt32) pLynxAsyncTxPCLData->pPCLPhysical);
  3528.         pPrevPCL->nextPCLAlt =
  3529.             (UInt32 *) EndianSwap32Bit ((UInt32) pLynxAsyncTxPCLData->pPCLPhysical);//zzz is this the best?
  3530.         pPrevLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pPrevPCL->refCon;
  3531.         pPrevLynxAsyncTxPCLData->pNextPCL = pPCL;
  3532.     }
  3533.     else
  3534.     {
  3535.         pLynxFWIMData->pNextAsyncTxPCL = pPCL;
  3536.     }
  3537.  
  3538.     // Check for asynchronous transmit done.
  3539.     if (pLynxFWIMData->asyncTxDoneFlag)
  3540.     {
  3541.         // Restart async transmit PCL program at new PCL if it's still unused.
  3542.         if (pPCL->status == EndianSwapImm32Bit (kLynxInvalidStatus))
  3543.             LynxFWIMStartAsyncTxPCLProgram (pLynxFWIMData, pPCL);
  3544.     }
  3545.  
  3546.     // New PCL is now last.
  3547.     pLynxFWIMData->pLastAsyncTxPCL = pPCL;
  3548. }
  3549.  
  3550.  
  3551. ////////////////////////////////////////////////////////////////////////////////
  3552. //
  3553. // LynxFWIMCreateAsyncTxDummyPCL
  3554. //
  3555. //   This proc creates a dummy PCL for starting the async transmit PCL program.
  3556. //
  3557.  
  3558. static void LynxFWIMCreateAsyncTxDummyPCL(
  3559.     LynxFWIMDataPtr                pLynxFWIMData)
  3560. {
  3561.     LynxAsyncTxPCLDataPtr        pLynxAsyncTxPCLData;
  3562.     LynxPCLPtr                    pPCL;
  3563.  
  3564.     // Just fill in the basics.
  3565.     pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDummyPCL]);
  3566.     pLynxAsyncTxPCLData = &(pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDummyPCL]);
  3567.     pLynxAsyncTxPCLData->pLynxFWIMData = pLynxFWIMData;
  3568.     pLynxAsyncTxPCLData->pPCLPhysical =
  3569.         pLynxFWIMData->asyncXmitPCLPhys + (kAsyncTxDummyPCL * sizeof (LynxPCL));
  3570.     pPCL->refCon = (UInt32) pLynxAsyncTxPCLData;
  3571. }
  3572.  
  3573.  
  3574. ////////////////////////////////////////////////////////////////////////////////
  3575. //
  3576. // LynxFWIMCreateAsyncTxDonePCLSegment
  3577. //
  3578. //   This proc creates the async transmit done PCL segment.
  3579. //
  3580.  
  3581. static void LynxFWIMCreateAsyncTxDonePCLSegment(
  3582.     LynxFWIMDataPtr                pLynxFWIMData)
  3583. {
  3584.     LynxFWIMDataPtr                pPhysLynxFWIMData;
  3585.     LynxAsyncTxPCLDataPtr        pLynxAsyncTxPCLData;
  3586.     LynxPCLPtr                    pPCL;
  3587.  
  3588.     // Get physical pointer to FWIM data.
  3589.     pPhysLynxFWIMData = pLynxFWIMData->fwimDataPhys;
  3590.  
  3591.     // Set up PCL to set done flag.
  3592.     pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDonePCL]);
  3593.     pPCL->nextPCL = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  3594.     pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  3595.     pLynxAsyncTxPCLData = &(pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDonePCL]);
  3596.     pLynxAsyncTxPCLData->pLynxFWIMData = pLynxFWIMData;
  3597.     pLynxAsyncTxPCLData->pPCLPhysical =
  3598.         pLynxFWIMData->asyncXmitPCLPhys + (kAsyncTxDonePCL * sizeof (LynxPCL));
  3599.     pPCL->refCon = (UInt32) pLynxAsyncTxPCLData;
  3600.     pPCL->status = EndianSwapImm32Bit (kLynxInvalidStatus);
  3601.     pPCL->remaining = EndianSwapImm32Bit (0);
  3602.     pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
  3603.  
  3604.     // Set done flag.
  3605.     pLynxFWIMData->asyncTxDoneFlag = 0xFFFFFFFF;
  3606.     pPCL->buffer[0].control =
  3607.         EndianSwapImm32Bit ((kLynxDMA_STORE1 << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
  3608.     pPCL->buffer[0].address =
  3609.         (UInt32 *) EndianSwap32Bit ((UInt32) &(pPhysLynxFWIMData->asyncTxDoneFlag));
  3610.  
  3611.     // Set PCL segment in FWIM data.
  3612.     pLynxFWIMData->asyncTxDonePCLSegment = pPCL;
  3613. }
  3614.  
  3615.  
  3616. ////////////////////////////////////////////////////////////////////////////////
  3617. //
  3618. // LynxFWIMCreateAsyncTxDataPCL
  3619. //
  3620. //   This proc creates a data PCL for the async transmit PCL program.
  3621. //
  3622.  
  3623. static void LynxFWIMCreateAsyncTxDataPCL(
  3624.     LynxFWIMDataPtr                pLynxFWIMData)
  3625. {
  3626.     LynxAsyncTxPCLDataPtr        pLynxAsyncTxPCLData;
  3627.     LynxPCLPtr                    pPCL;
  3628.  
  3629.     // Just fill in the basics.
  3630.     pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]);
  3631.     pLynxAsyncTxPCLData = &(pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDataPCL]);
  3632.     pLynxAsyncTxPCLData->pLynxFWIMData = pLynxFWIMData;
  3633.     pLynxAsyncTxPCLData->pPCLPhysical =
  3634.         pLynxFWIMData->asyncXmitPCLPhys + (kAsyncTxDataPCL * sizeof (LynxPCL));
  3635.     pPCL->refCon = (UInt32) pLynxAsyncTxPCLData;
  3636. }
  3637.  
  3638.  
  3639. ////////////////////////////////////////////////////////////////////////////////
  3640. //
  3641. // LynxFWIMStartAsyncTxPCLProgram
  3642. //
  3643. //   This proc starts the async transmit PCL program.
  3644. //
  3645.  
  3646. static void LynxFWIMStartAsyncTxPCLProgram(
  3647.     LynxFWIMDataPtr                pLynxFWIMData,
  3648.     LynxPCLPtr                    pStartPCL)
  3649. {
  3650.     LynxRegistersPtr            pLynxRegs;
  3651.     LynxAsyncTxPCLDataPtr        pLynxAsyncTxPCLData,
  3652.                                 pStartLynxAsyncTxPCLData;
  3653.     LynxPCLPtr                    pPCL;
  3654.     Boolean                        asyncTxReady = false;
  3655.  
  3656.     // Clear done flag.
  3657.     pLynxFWIMData->asyncTxDoneFlag = 0;
  3658.  
  3659.     // Get pointer to link registers and start PCL's data.
  3660.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3661.  
  3662.     // Quiet the DMA channel.
  3663.     pLynxRegs->dmaChannel[kTransmitDMA].control = EndianSwapImm32Bit (0);
  3664.     SynchronizeIO();
  3665.  
  3666.     // Start the PCL program at the given PCL.
  3667.     pPCL = &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDummyPCL]);
  3668.     pStartLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pStartPCL->refCon;
  3669.     pPCL->nextPCL =
  3670.         (UInt32 *) EndianSwap32Bit ((UInt32) pStartLynxAsyncTxPCLData->pPCLPhysical);
  3671.     pPCL->nextPCLAlt =
  3672.         (UInt32 *) EndianSwap32Bit ((UInt32) pStartLynxAsyncTxPCLData->pPCLPhysical);
  3673.     pLynxAsyncTxPCLData = (LynxAsyncTxPCLDataPtr) pPCL->refCon;
  3674.     pLynxRegs->dmaChannel[kTransmitDMA].curPCLAddr =
  3675.         EndianSwap32Bit ((UInt32) pLynxAsyncTxPCLData->pPCLPhysical);
  3676.     SynchronizeIO();
  3677.  
  3678.     // Enable the DMA.
  3679.     pLynxRegs->dmaChannel[kTransmitDMA].ready =
  3680.         EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
  3681.     SynchronizeIO();
  3682.     pLynxRegs->dmaChannel[kTransmitDMA].control =
  3683.         EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  3684.     SynchronizeIO();
  3685. }
  3686.  
  3687.  
  3688. ////////////////////////////////////////////////////////////////////////////////
  3689. //
  3690. // LynxFWIMSetLinkControl
  3691. //
  3692. //   This proc sets the link control register and updates various link control
  3693. // parameters.
  3694. //
  3695.  
  3696. static void LynxFWIMSetLinkControl(
  3697.     LynxFWIMDataPtr                pLynxFWIMData,
  3698.     UInt32                        linkControl)
  3699. {
  3700.     LynxRegistersPtr            pLynxRegs;
  3701.  
  3702.     // Set asyncRxOverflowSetLinkControl in FWIM data.
  3703.     //zzz still have synchronization issues with async receive DMA
  3704.     pLynxFWIMData->asyncRxOverflowSetLinkControl =
  3705.         EndianSwap32Bit (linkControl | kLynxBUSY_CNTRL);
  3706.  
  3707.     // Set linkControl register.
  3708.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3709.     pLynxRegs->linkControl = EndianSwap32Bit (linkControl);
  3710.     SynchronizeIO ();
  3711. }
  3712.  
  3713.  
  3714. ////////////////////////////////////////////////////////////////////////////////
  3715. //
  3716. // LynxFWIMSetAsyncRxComparatorMask1
  3717. //
  3718. //   This proc sets the async receive mask1 comparator and updates some
  3719. // parameters.
  3720. //
  3721.  
  3722. static void LynxFWIMSetAsyncRxComparatorMask1(
  3723.     LynxFWIMDataPtr                pLynxFWIMData,
  3724.     UInt32                        mask1)
  3725. {
  3726.     LynxRegistersPtr            pLynxRegs;
  3727.  
  3728.     // Set asyncRxOverflowSetPCLComparator in FWIM data.
  3729.     //zzz still have synchronization issues with async receive DMA
  3730.     pLynxFWIMData->asyncRxOverflowSetPCLComparator =
  3731.         EndianSwap32Bit (mask1 & ~kLynxEN_CH_COMPARE);
  3732.  
  3733.     // Set comparator register.
  3734.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3735.     pLynxRegs->dmaComparator[kAsyncDMA].mask1 = EndianSwap32Bit (mask1);
  3736.     SynchronizeIO ();
  3737. }
  3738.  
  3739.  
  3740. ////////////////////////////////////////////////////////////////////////////////
  3741. //
  3742. // LynxFWIMWriteATF
  3743. //
  3744. //   Common code for writing an ATF packet
  3745. //
  3746.  
  3747. static OSStatus LynxFWIMWriteATF(
  3748.     LynxFWIMDataPtr                pLynxFWIMData,
  3749.     UInt32                        transmitType,
  3750.     UInt32                        speed,
  3751.     UInt32                        baseCount,        // count [1-4] of quads below:
  3752.     UInt32                        data1,
  3753.     UInt32                        data2,
  3754.     UInt32                        data3,
  3755.     UInt32                        data4,
  3756.     UInt32                        extCount,        // count in BYTES of data below:
  3757.     UInt32                        *extData)
  3758. {
  3759.     LynxRegistersPtr            pLynxRegs;
  3760.     IOPreparationID                ioPreparationID;
  3761.     UInt32                        dataBuffer[4];
  3762.     UInt32                        pclControl;
  3763.     AbsoluteTime                timeoutAbsolute, timeLeft;
  3764.     UInt32                        patience;
  3765.     OSStatus                    status = noErr;
  3766.  
  3767. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMWriteATF");
  3768.  
  3769.     // Get pointer to link registers.
  3770.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  3771.  
  3772.     // Set up data PCL.
  3773.     dataBuffer[0] = data1;
  3774.     dataBuffer[1] = data2;
  3775.     dataBuffer[2] = data3;
  3776.     dataBuffer[3] = data4;
  3777.     pclControl = (transmitType << kLynxDMA_CMDPhase) | kLynxDMA_WAIT_FOR_STATUS;
  3778.     if (speed == kFWSpeed200MBit)
  3779.         pclControl |= kLynxDMA200mbps << kLynxDMA_xmit_spd_codePhase;
  3780.     LynxFWIMBuildAsyncTxPCL (pLynxFWIMData,
  3781.                              &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]),
  3782.                              &ioPreparationID,
  3783.                              pclControl,
  3784.                              (Ptr) &dataBuffer[0],
  3785.                              baseCount * sizeof (UInt32),
  3786.                              (Ptr) extData,
  3787.                              extCount);
  3788.  
  3789.     // Add data PCL to async transmit program and start.
  3790.     LynxFWIMAddAsyncTxPCL (&(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]));
  3791.  
  3792. #if 0
  3793.     // This way is bad.  We hammer the link control register via PCI.
  3794.     // That causes FIFO underflows on big packets.
  3795.     // Wait for async transmit program to end, or TX to be disabled (due to bus reset).
  3796.     while ((EndianSwap32Bit(pLynxRegs->linkControl) & kLynxTX_ASYNC_EN) &&
  3797.            !(pLynxFWIMData->asyncTxDoneFlag));
  3798. #endif
  3799.  
  3800.     // This still isn't great.  We should just return, and then handle completion or
  3801.     // failure later, when an interrupt or timer goes off.
  3802.     
  3803.     // Wait for async transmit program to end, or TX to be disabled (due to bus reset).
  3804.     // Check TX disable only once per millisecond.  Try this for at most 50 milliseconds.
  3805.  
  3806.     timeoutAbsolute =
  3807.         AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (durationMillisecond));
  3808.     patience = 50;
  3809.  
  3810.     while (!(pLynxFWIMData->asyncTxDoneFlag))
  3811.     {
  3812.         // Check only rarely for bus reset
  3813.         timeLeft = SubAbsoluteFromAbsolute (UpTime (), timeoutAbsolute);  // returns 0 if negative
  3814.         if (AbsoluteToDuration (timeLeft) == 0)        
  3815.         {
  3816.             if ((!patience) || !(EndianSwap32Bit(pLynxRegs->linkControl) & kLynxTX_ASYNC_EN))
  3817.             {
  3818.                 pLynxRegs->dmaChannel[kTransmitDMA].control = EndianSwapImm32Bit (0);
  3819.                 SynchronizeIO ();
  3820.                 pLynxFWIMData->asyncTxDoneFlag = 0xFFFFFFFF;
  3821.             }
  3822.             else
  3823.             {
  3824.                 timeoutAbsolute =
  3825.                     AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (durationMillisecond));
  3826.                 patience--;
  3827.             }        
  3828.         }
  3829.     }
  3830.     
  3831.     // Clean up transmission.
  3832.     CheckpointIO (ioPreparationID, kNilOptions);
  3833.     pLynxFWIMData->pNextAsyncTxPCL =
  3834.         pLynxFWIMData->lynxAsyncTxPCLDataList[kAsyncTxDataPCL].pNextPCL;
  3835.  
  3836.     return status;
  3837. }
  3838.  
  3839.  
  3840. ////////////////////////////////////////////////////////////////////////////////
  3841. //
  3842. // LynxFWIMBuildAsyncTxPCL
  3843. //
  3844. //   This proc builds an asynchronous transmit PCL from the given parameters.
  3845. // buffer1 is assumed to be small.  It is usually a packet header.  buffer2 is
  3846. // assumed to be larger and typically is a packet payload.
  3847. //
  3848.  
  3849. static OSStatus    LynxFWIMBuildAsyncTxPCL(
  3850.     LynxFWIMDataPtr                pLynxFWIMData,
  3851.     LynxPCLPtr                    pPCL,
  3852.     IOPreparationID                *pIOPreparationID,
  3853.     UInt32                        pclControl,
  3854.     Ptr                            buffer1,
  3855.     UInt32                        size1,
  3856.     Ptr                            buffer2,
  3857.     UInt32                        size2)
  3858. {
  3859.     IOPreparationTable            ioPreparationTable;
  3860.     PhysicalAddress                physicalMapping[kMaxBufPage];
  3861.     UInt32                        pageSize,
  3862.                                 pageShift;
  3863.     UInt32                        numPages;
  3864.     Ptr                            preparedBuffer;
  3865.     UInt32                        seg1Size,
  3866.                                 seg2Size,
  3867.                                 seg3Size;
  3868.     UInt32                        seg2AlignSize;
  3869.     UInt32                        transferSize;
  3870.     UInt32                        pclBufferNum;
  3871.     UInt32                        pageNum;
  3872.     OSStatus                    status = noErr;
  3873.  
  3874.     // Get some FWIM parameters.
  3875.     pageSize = pLynxFWIMData->pageSize;
  3876.     pageShift = pLynxFWIMData->pageShift;
  3877.     preparedBuffer = pLynxFWIMData->asyncXmitBuf;
  3878.  
  3879.     // Do initial PCL set up.
  3880.     pPCL->nextPCL = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  3881.     pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  3882.     pPCL->status = EndianSwapImm32Bit (0);
  3883.     pPCL->remaining = EndianSwapImm32Bit (0);
  3884.     pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
  3885.  
  3886.     // Set up initial segment sizes, PCL buffer number, and ioPreparationTable.
  3887.     seg1Size = size1;
  3888.     seg2Size = size2;
  3889.     seg3Size = 0;
  3890.     pclBufferNum = 0;
  3891.     ioPreparationTable.preparationID = kInvalidID;
  3892.  
  3893.     // Add buffer1 to our prepared buffer.
  3894.     if (size1 > 0)
  3895.     {
  3896.         BlockCopy (buffer1, preparedBuffer, size1);
  3897.         preparedBuffer += size1;
  3898.     }
  3899.  
  3900.     // Add data from buffer2 to our prepared buffer to 32 byte align second segment.
  3901.     if ((((UInt32) buffer2) & 31) > 0)
  3902.         seg2AlignSize = 32 - (((UInt32) buffer2) & 31);
  3903.     else
  3904.         seg2AlignSize = 0;
  3905.     if (seg2AlignSize > size2)
  3906.         seg2AlignSize = size2;
  3907.     if (seg2AlignSize > 0)
  3908.     {
  3909.         BlockCopy (buffer2, preparedBuffer, seg2AlignSize);
  3910.         preparedBuffer += seg2AlignSize;
  3911.         seg1Size += seg2AlignSize;
  3912.         buffer2 += seg2AlignSize;
  3913.         seg2Size -= seg2AlignSize;
  3914.     }
  3915.  
  3916.     // Add prepared buffer to PCL.
  3917.     pPCL->buffer[pclBufferNum].control = EndianSwap32Bit (pclControl | seg1Size);
  3918.     pPCL->buffer[pclBufferNum].address =
  3919.         (UInt32 *) EndianSwap32Bit ((UInt32) pLynxFWIMData->asyncXmitBufPhys);
  3920.     pclBufferNum++;
  3921.  
  3922.     // Add rest of buffer2 to PCL.
  3923.     if (seg2Size > 0)
  3924.     {
  3925.         // Set up IO preparation table.
  3926.         numPages = ((((UInt32) buffer2) + seg2Size - 1) >> pageShift) -
  3927.                    (((UInt32) buffer2) >> pageShift) + 1;
  3928.         ioPreparationTable.options = kIOLogicalRanges | kIOIsOutput;
  3929.         ioPreparationTable.addressSpace = kCurrentAddressSpaceID;
  3930.         ioPreparationTable.granularity = 0;
  3931.         ioPreparationTable.firstPrepared = 0;
  3932.         ioPreparationTable.mappingEntryCount = numPages;
  3933.         ioPreparationTable.logicalMapping = 0;
  3934.         ioPreparationTable.physicalMapping = physicalMapping;
  3935.         ioPreparationTable.rangeInfo.range.base = buffer2;
  3936.         ioPreparationTable.rangeInfo.range.length = seg2Size;
  3937.  
  3938.         // Prepare.
  3939.         status = PrepareMemoryForIO (&ioPreparationTable);
  3940.     /*zzz*/
  3941.         if (status != noErr)
  3942.         {
  3943.             sprintf (debugStr, "PrepareMemoryForIO error %ld", status);
  3944.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  3945.         }
  3946.     /*zzz*/
  3947.  
  3948.         // Add pages to PCL.
  3949.         if (status == noErr)
  3950.         {
  3951.             // Compute first page transfer size.
  3952.             if (numPages > 1)
  3953.                 transferSize = pageSize - (((UInt32) buffer2) & (pageSize - 1));
  3954.             else
  3955.                 transferSize = seg2Size;
  3956.  
  3957.             // Add first page to PCL.
  3958.             pPCL->buffer[pclBufferNum].control =
  3959.                 EndianSwap32Bit (pclControl | transferSize);
  3960.             pPCL->buffer[pclBufferNum].address =
  3961.                 (UInt32 *) EndianSwap32Bit ((UInt32) physicalMapping[0]);
  3962.             pclBufferNum++;
  3963.  
  3964.             // Add rest of pages except last one to PCL.
  3965.             for (pageNum = 1; pageNum < (numPages - 1); pageNum++)
  3966.             {
  3967.                 // Add page to PCL.
  3968.                 pPCL->buffer[pclBufferNum].control =
  3969.                     EndianSwap32Bit (pclControl | pageSize);
  3970.                 pPCL->buffer[pclBufferNum].address =
  3971.                     (UInt32 *) EndianSwap32Bit ((UInt32) physicalMapping[pageNum]);
  3972.                 pclBufferNum++;
  3973.             }
  3974.  
  3975.             // Add last page to PCL.
  3976.             if (numPages > 1)
  3977.             {
  3978.                 transferSize = (((UInt32) buffer2) + seg2Size) & (pageSize - 1);
  3979.                 pPCL->buffer[pclBufferNum].control =
  3980.                     EndianSwap32Bit (pclControl | transferSize);
  3981.                 pPCL->buffer[pclBufferNum].address =
  3982.                     (UInt32 *) EndianSwap32Bit ((UInt32) physicalMapping[numPages - 1]);
  3983.                 pclBufferNum++;
  3984.             }
  3985.         }
  3986.     }
  3987.  
  3988.     // Add zero padding to PCL.
  3989.     if (status == noErr)
  3990.     {
  3991.         // Compute amount of zero padding.
  3992.         if ((size2 & 3) > 0)
  3993.         {
  3994.             seg3Size = 4 - (size2 & 3);
  3995.  
  3996.             // Use prepared buffer for zeros.
  3997.             ((UInt32 *) pLynxFWIMData->asyncXmitBuf)[128] = 0;
  3998.  
  3999.             // Add to PCL.
  4000.             pPCL->buffer[pclBufferNum].control =
  4001.                 EndianSwap32Bit (pclControl | seg3Size);
  4002.             pPCL->buffer[pclBufferNum].address =
  4003.                 (UInt32 *) EndianSwap32Bit ((UInt32) (pLynxFWIMData->asyncXmitBufPhys) + 512);
  4004.             pclBufferNum++;
  4005.         }
  4006.     }
  4007.  
  4008.     // Set last buffer.
  4009.     if (status == noErr)
  4010.         pPCL->buffer[pclBufferNum - 1].control |= EndianSwapImm32Bit (kLynxDMA_LAST_BUF);
  4011.  
  4012.     // Return ioPreparationID.
  4013.     if (status == noErr)
  4014.         *pIOPreparationID = ioPreparationTable.preparationID;
  4015.     else
  4016.         *pIOPreparationID = kInvalidID;
  4017.  
  4018.     return (status);
  4019. }
  4020.  
  4021.  
  4022. ////////////////////////////////////////////////////////////////////////////////
  4023. //
  4024. // LynxFWIMRead
  4025. //
  4026. //   This proc performs a read transaction on the FireWire bus.
  4027. //   We write the read command, the completion is handled elsewhere
  4028. //   when we get an interrupt for the receipt of the response.
  4029. //zzz what if timer goes off before request goes out???
  4030. //zzz check length against maximum packet size
  4031. //zzz should be set up to get acknowledgement
  4032. //
  4033.  
  4034. static OSStatus    LynxFWIMRead(
  4035.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  4036.     UInt32                        *pCommandAcceptance)
  4037. {
  4038.     FWIMCommandParamsPtr        pFWIMCommandParams;
  4039.     LynxFWIMDataPtr                pLynxFWIMData; 
  4040.     LynxRegistersPtr            pLynxRegs;
  4041.     UInt32                        data1, data2, data3, data4;
  4042.     UInt32                        sourceID;
  4043.     AbsoluteTime                timeoutAbsolute;
  4044.     OSStatus                    status = noErr;
  4045.  
  4046. //    FWDebugStr ((ConstStr255Param) "\p(Lynx) LynxFWIMRead");
  4047.  
  4048.     // Get our internal data.
  4049.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  4050.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  4051.  
  4052.     // Set pending command.
  4053.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
  4054.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  4055.  
  4056.     // Get pointer to link registers.
  4057.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4058.  
  4059.     // already has bit alignment we'll need later...
  4060.     sourceID = EndianSwap32Bit (pLynxRegs->busNumberNodeNumber);
  4061.     
  4062.     // Check if generation is up to date.
  4063.     if ((!(pLynxFWIMData->generationValid)) ||
  4064.         (pFWIMAsynchCommandParams->generation != pLynxFWIMData->generation))
  4065.     {
  4066.         status = busReconfiguredErr;
  4067.     }
  4068.  
  4069. // If we wanted to be really clever, we could program up a spare DMA channel to
  4070. // match the sourceID, tCode, and tLabel, causing the response to be DMAed
  4071. // directly into the desired location, skipping an in-memory copy.
  4072.  
  4073. // Warning - it is ESSENTIAL that reads which fail trigger the timeout handler.
  4074. // FSL can't handle reads that just "vanish".  But, rather than go thru the handler,
  4075. // maybe we can return a failure below.
  4076.  
  4077. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMRead - setting timer for failure");
  4078.     // Set a timeout timer.
  4079.     if (status == noErr)
  4080.     {
  4081.         timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (pFWIMAsynchCommandParams->timeout));
  4082.         status = SetInterruptTimer
  4083.                     (&timeoutAbsolute,
  4084.                      LynxFWIMReadRequestTimeoutHandler,
  4085.                      pFWIMAsynchCommandParams,
  4086.                      &(pLynxFWIMData->requestTimeoutTimerID));
  4087.         if (status == noErr)
  4088.             pLynxFWIMData->requestTimeoutTimerSet = true;
  4089.     }
  4090.  
  4091. // sometimes FSL tries to read from the local node, which won't work.
  4092. // rather than bothering the DMA engine, just let the timeout timer
  4093. // return the error.  (return now - NYI)
  4094.  
  4095.     // Write read request to ATF.
  4096.     if (status == noErr)
  4097.     {
  4098. // Need to send at correct speed (WriteAFT always sends at 100)
  4099.         pLynxFWIMData->transactionLabel =
  4100.             (pLynxFWIMData->transactionLabel + 1) & 0x3F;
  4101.  
  4102.         // Header quad common to quadlet and block:
  4103.         data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
  4104.         data1 |= (pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase);
  4105.         data1 |= (kFWAsynchNew << kFWAsynchRtPhase);
  4106.         
  4107.         // Packet address same for both:
  4108.         data2 = sourceID;
  4109.         data2 |= (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
  4110.         data3 = pFWIMAsynchCommandParams->addressLo;
  4111.         
  4112.         if (pFWIMAsynchCommandParams->length == 4)
  4113.         { // Quadlet request.
  4114.                         
  4115.             pLynxFWIMData->tCode = kFWTCodeReadQuadlet;
  4116.             data1 |= (kFWTCodeReadQuadlet << kFWPacketTCodePhase);
  4117.  
  4118.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 3, data1, data2, data3, 0, 0, 0);
  4119.         }
  4120.         else
  4121.         { // Block request.
  4122.  
  4123.             pLynxFWIMData->tCode = kFWTCodeReadBlock;
  4124.             data1 |= (kFWTCodeReadBlock << kFWPacketTCodePhase);
  4125.  
  4126.             data4 = pFWIMAsynchCommandParams->length << kFWAsynchDataLengthPhase;
  4127.             
  4128.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4, 0, 0);
  4129.         }
  4130.     }
  4131.  
  4132.     // Complete command on error.
  4133.     if (status != noErr)
  4134.     {
  4135.         pLynxFWIMData->pPendingFWIMCommand = nil;
  4136.         status = FWIMCommandIsComplete
  4137.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  4138.                      status);
  4139.     }
  4140.  
  4141.     // Return command acceptance.
  4142.     //zzz what if we call FWIMCommandIsComplete before returning this???
  4143.     //zzz well, it still works, but will it always?
  4144.     //zzz actually, when we switch to the dispatch table, each routine can return
  4145.     //zzz the appropriate acceptance, so don't worry about it for now.
  4146.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  4147.  
  4148.     return (status);
  4149. }
  4150.  
  4151.  
  4152. ////////////////////////////////////////////////////////////////////////////////
  4153. //
  4154. // LynxFWIMReadResponse
  4155. //
  4156. //   This proc sends a read response packet.
  4157. //zzz check length against maximum packet size
  4158. //zzz should be set up to get acknowledgement
  4159. //
  4160.  
  4161. static OSStatus    LynxFWIMReadResponse(
  4162.     FWIMAsynchResponseCommandParamsPtr
  4163.                                 pFWIMAsynchResponseCommandParams,
  4164.     UInt32                        *pCommandAcceptance)
  4165. {
  4166.     FWIMCommandParamsPtr        pFWIMCommandParams;
  4167.     LynxFWIMDataPtr                pLynxFWIMData; 
  4168.     LynxRegistersPtr            pLynxRegs;
  4169.     UInt32                        data1, data2, data4;
  4170.     UInt32                        sourceID;
  4171.     UInt32                        transactionLabel;
  4172.     UInt32                        responseCode;
  4173.     OSStatus                    status = noErr;
  4174.  
  4175.     // Get our internal data.
  4176.     pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
  4177.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  4178.  
  4179.     // Set pending command.
  4180.     pLynxFWIMData->pPendingFWIMResponseCommand =
  4181.         (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
  4182.  
  4183.     // Get pointer to link registers.
  4184.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4185.  
  4186.     // already has bit alignment we'll need later...
  4187.     sourceID = EndianSwap32Bit (pLynxRegs->busNumberNodeNumber);//zzz read out of FWIM data
  4188.     
  4189.     // Check if generation is up to date.
  4190.     if ((!(pLynxFWIMData->generationValid)) ||
  4191.         (pFWIMAsynchResponseCommandParams->generation != pLynxFWIMData->generation))
  4192.     {
  4193.         status = busReconfiguredErr;
  4194.     }
  4195.  
  4196.     // Write read response to ATF.
  4197.     if (status == noErr)
  4198.     {
  4199.         // Compute transaction label and response code.
  4200.         transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
  4201.                             kFWTransactionDescriptorTLabel) >>
  4202.                            kFWTransactionDescriptorTLabelPhase;
  4203.         responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
  4204.                         kFWResponseDataRCode) >>
  4205.                        kFWResponseDataRCodePhase;
  4206.  
  4207.         // packet control header goes in quad 1
  4208.         data1 = pFWIMAsynchResponseCommandParams->destinationID << kFWAsynchSourceIDPhase;
  4209.         data1 |= transactionLabel << kFWAsynchTLabelPhase;
  4210.         data1 |= kFWAsynchNew << kFWAsynchRtPhase;
  4211.     
  4212.         // packet destination node ID and response code go in quad 2
  4213.         data2 = sourceID;
  4214.         data2 |= responseCode << kFWAsynchRCodePhase;
  4215.     
  4216.         // packet payload goes in quad 4
  4217.         data4 = (*((UInt32 *) pFWIMAsynchResponseCommandParams->buffer));
  4218.     
  4219.         if (pFWIMAsynchResponseCommandParams->length == 4)
  4220.         { // Quadlet request.
  4221.                         
  4222.             data1 |= kFWTCodeReadQuadletResponse << kFWPacketTCodePhase;
  4223.  
  4224.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, 0, 0);
  4225.         }
  4226.         else
  4227.         { // Block request.
  4228.  
  4229.             data1 |= kFWTCodeReadBlockResponse << kFWPacketTCodePhase;
  4230.  
  4231.             data4 = pFWIMAsynchResponseCommandParams->length << kFWAsynchDataLengthPhase;
  4232.             
  4233.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, pFWIMAsynchResponseCommandParams->length, (UInt32 *) pFWIMAsynchResponseCommandParams->buffer);
  4234.         }
  4235.     }
  4236.  
  4237.     // Complete command on error.
  4238.     //zzz assume success for now.  should check ack code for success.
  4239. //zzz    if (status != noErr)
  4240.     {
  4241.         pLynxFWIMData->pPendingFWIMResponseCommand = nil;
  4242.         status = FWIMCommandIsComplete
  4243.                     (pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID,
  4244.                      status);
  4245.     }
  4246.  
  4247.     // Return command acceptance.
  4248.     //zzz what if we call FWIMCommandIsComplete before returning this???
  4249.     //zzz well, it still works, but will it always?
  4250.     //zzz actually, when we switch to the dispatch table, each routine can return
  4251.     //zzz the appropriate acceptance, so don't worry about it for now.
  4252.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  4253.  
  4254.     return (status);
  4255. }
  4256.  
  4257.  
  4258. ////////////////////////////////////////////////////////////////////////////////
  4259. //
  4260. // LynxFWIMWrite
  4261. //
  4262. //   This proc performs a write transaction on the FireWire bus.
  4263. //zzz what if timer goes off before request goes out??? A: Execute this proc
  4264. //zzz at secondary interrupt level
  4265. //zzz check length against maximum packet size
  4266. //zzz should be set up to get acknowledgement
  4267. //
  4268.  
  4269. static OSStatus    LynxFWIMWriteTimer(
  4270.     void                        *p1,
  4271.     void                        *p2)
  4272. {
  4273.     UInt32                        commandAcceptance;
  4274.     OSStatus                    status = noErr;
  4275.  
  4276.     status = LynxFWIMWrite ((FWIMAsynchCommandParamsPtr) p1, &commandAcceptance);
  4277.     return (status);
  4278. }
  4279.  
  4280. static OSStatus    LynxFWIMWrite(
  4281.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  4282.     UInt32                        *pCommandAcceptance)
  4283. {
  4284.     FWIMCommandParamsPtr        pFWIMCommandParams;
  4285.     LynxFWIMDataPtr                pLynxFWIMData; 
  4286.     LynxRegistersPtr            pLynxRegs;
  4287.     OSStatus                    status = noErr;
  4288.     UInt32                        data1, data2, data3, data4;
  4289.     UInt32                        sourceID;
  4290.  
  4291.     static UInt32 debug = 0;
  4292.  
  4293. //    sprintf (debugStr, "FWIM Write %ld bytes", (long) pFWIMAsynchCommandParams->length);
  4294. //    FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  4295.     
  4296.     // Get our internal data.
  4297.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  4298.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  4299.  
  4300.     // Set pending command.
  4301.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
  4302.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  4303.  
  4304.     // Timer is off.
  4305.     pLynxFWIMData->requestTimeoutTimerSet = false;
  4306.  
  4307.     // Get pointer to link registers.
  4308.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4309.  
  4310.     // Check if generation is up to date.
  4311.     if ((!(pLynxFWIMData->generationValid)) ||
  4312.         (pFWIMAsynchCommandParams->generation != pLynxFWIMData->generation))
  4313.     {
  4314.         status = busReconfiguredErr;
  4315.     }
  4316.  
  4317.     //zzz need to set a timeout timer in case we get a ack_pending
  4318.  
  4319.     // already has bit alignment we'll need later...
  4320.     sourceID = EndianSwap32Bit (pLynxRegs->busNumberNodeNumber);
  4321.  
  4322.     // Write write request to ATF.
  4323.     if (status == noErr)
  4324.     {
  4325.         if (pFWIMAsynchCommandParams->length == 4)
  4326.         { // Quadlet request.
  4327.             // Write packet control header.
  4328.             data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
  4329.  
  4330.             pLynxFWIMData->transactionLabel =
  4331.                 (pLynxFWIMData->transactionLabel + 1) & 0x3F;
  4332.             pLynxFWIMData->tCode = kFWTCodeWriteQuadlet;
  4333.             data1 |= pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase;
  4334.             data1 |= kFWAsynchNew << kFWAsynchRtPhase;
  4335.             data1 |= kFWTCodeWriteQuadlet << kFWPacketTCodePhase;
  4336.  
  4337.             // Write packet address.
  4338.             data2 = sourceID;
  4339.             data2 |= (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
  4340.             data3 = pFWIMAsynchCommandParams->addressLo;
  4341.  
  4342.             // Write packet payload.
  4343.             data4 = (*((UInt32 *) pFWIMAsynchCommandParams->buffer));
  4344.  
  4345.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4, 0, 0);
  4346.         }
  4347.         else
  4348.         { // Block request.
  4349.             // Write packet control header.
  4350.             data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
  4351.  
  4352.             pLynxFWIMData->transactionLabel =
  4353.                 (pLynxFWIMData->transactionLabel + 1) & 0x3F;
  4354.             pLynxFWIMData->tCode = kFWTCodeWriteBlock;
  4355.             data1 |= pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase;
  4356.             data1 |= kFWAsynchNew << kFWAsynchRtPhase;
  4357.             data1 |= kFWTCodeWriteBlock << kFWPacketTCodePhase;
  4358.  
  4359.             // Write packet address.
  4360.             data2 = sourceID;
  4361.             data2 |= (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
  4362.             data3 = pFWIMAsynchCommandParams->addressLo;
  4363.  
  4364.             // Write request length.
  4365.             data4 = pFWIMAsynchCommandParams->length << kFWAsynchDataLengthPhase;
  4366.  
  4367.             LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4,
  4368.                              pFWIMAsynchCommandParams->length,
  4369.                              (UInt32 *) pFWIMAsynchCommandParams->buffer);
  4370.         }
  4371.     }
  4372.  
  4373.     // Complete command on error.
  4374.     if (status != noErr)
  4375.     {
  4376.         pLynxFWIMData->pPendingFWIMCommand = nil;
  4377.         status = FWIMCommandIsComplete
  4378.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  4379.                      status);
  4380.     }
  4381.     else
  4382.     {
  4383.         // We no longer take TxRdy interrupt, instead, the status should already be waiting for us.
  4384.         //zzz We probably should take an interrupt.  Other transmit stuff (like isoch) could
  4385.         //zzz be blocking this transmission for relatively long periods of time.
  4386.         LynxFWIMAckSecondaryInterruptHandler
  4387.             (pLynxFWIMData, &(pLynxFWIMData->asyncXmitPCL[kAsyncTxDataPCL]));
  4388.     }
  4389.  
  4390.     // Return command acceptance.
  4391.     //zzz what if we call FWIMCommandIsComplete before returning this???
  4392.     //zzz well, it still works, but will it always?
  4393.     //zzz actually, when we switch to the dispatch table, each routine can return
  4394.     //zzz the appropriate acceptance, so don't worry about it for now.
  4395.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  4396.  
  4397.     return (status);
  4398. }
  4399.  
  4400.  
  4401. ////////////////////////////////////////////////////////////////////////////////
  4402. //
  4403. // LynxFWIMWriteResponse
  4404. //
  4405. //   This proc sends a write response packet.
  4406. //zzz should be set up to get acknowledgement
  4407. //
  4408.  
  4409. static OSStatus    LynxFWIMWriteResponse(
  4410.     FWIMAsynchResponseCommandParamsPtr
  4411.                                 pFWIMAsynchResponseCommandParams,
  4412.     UInt32                        *pCommandAcceptance)
  4413. {
  4414.     FWIMCommandParamsPtr        pFWIMCommandParams;
  4415.     LynxFWIMDataPtr                pLynxFWIMData; 
  4416.     LynxRegistersPtr            pLynxRegs;
  4417.     UInt32                        data1, data2;
  4418.     UInt32                        sourceID;
  4419.     UInt32                        transactionLabel;
  4420.     UInt32                        responseCode;
  4421.     OSStatus                    status = noErr;
  4422.  
  4423.     // Get our internal data.
  4424.     pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
  4425.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  4426.  
  4427.     // Set pending command.
  4428.     pLynxFWIMData->pPendingFWIMResponseCommand =
  4429.         (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
  4430.  
  4431.     // Get pointer to link registers.
  4432.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4433.  
  4434.     // already has bit alignment we'll need later...
  4435.     sourceID = EndianSwap32Bit (pLynxRegs->busNumberNodeNumber);//zzz read out of FWIM data
  4436.  
  4437.     // Check if generation is up to date.
  4438.     if ((!(pLynxFWIMData->generationValid)) ||
  4439.         (pFWIMAsynchResponseCommandParams->generation != pLynxFWIMData->generation))
  4440.     {
  4441.         status = busReconfiguredErr;
  4442.     }
  4443.  
  4444.     // Write write response to ATF.
  4445.     if (status == noErr)
  4446.     {
  4447.         // Compute transaction label and response code.
  4448.         transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
  4449.                             kFWTransactionDescriptorTLabel) >>
  4450.                            kFWTransactionDescriptorTLabelPhase;
  4451.         responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
  4452.                         kFWResponseDataRCode) >>
  4453.                        kFWResponseDataRCodePhase;
  4454.  
  4455.         // packet control header goes in quad 1
  4456.         data1 = pFWIMAsynchResponseCommandParams->destinationID << kFWAsynchSourceIDPhase;
  4457.         data1 |= kFWTCodeWriteResponse << kFWPacketTCodePhase;
  4458.         data1 |= transactionLabel << kFWAsynchTLabelPhase;
  4459.         data1 |= kFWAsynchNew << kFWAsynchRtPhase;
  4460.     
  4461.         // packet destination node ID and response code go in quad 2
  4462.         data2 = sourceID;
  4463.         data2 |= responseCode << kFWAsynchRCodePhase;
  4464.  
  4465.         LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 3, data1, data2, 0, 0, 0, 0);
  4466.     }
  4467.  
  4468.     // Complete command on error.
  4469.     //zzz assume success for now.  should check ack code for success.
  4470. //zzz    if (status != noErr)
  4471.     {
  4472.         pLynxFWIMData->pPendingFWIMResponseCommand = nil;
  4473.         status = FWIMCommandIsComplete
  4474.                     (pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID,
  4475.                      status);
  4476.     }
  4477.  
  4478.     // Return command acceptance.
  4479.     //zzz what if we call FWIMCommandIsComplete before returning this???
  4480.     //zzz well, it still works, but will it always?
  4481.     //zzz actually, when we switch to the dispatch table, each routine can return
  4482.     //zzz the appropriate acceptance, so don't worry about it for now.
  4483.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  4484.  
  4485.     return (status);
  4486. }
  4487.  
  4488.  
  4489. ////////////////////////////////////////////////////////////////////////////////
  4490. //
  4491. // LynxFWIMLock
  4492. //
  4493. //   This proc performs a lock transaction on the FireWire bus.
  4494. //zzz what if timer goes off before request goes out??? A: Execute this proc
  4495. //zzz at secondary interrupt level
  4496. //zzz check length against maximum packet size
  4497. //zzz should be set up to get acknowledgement
  4498. //
  4499.  
  4500. static OSStatus    LynxFWIMLock(
  4501.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams,
  4502.     UInt32                        *pCommandAcceptance)
  4503. {
  4504.     FWIMCommandParamsPtr        pFWIMCommandParams;
  4505.     LynxFWIMDataPtr                pLynxFWIMData; 
  4506.     LynxRegistersPtr            pLynxRegs;
  4507.     UInt32                        data1, data2, data3, data4, sourceID;
  4508.     AbsoluteTime                timeoutAbsolute;
  4509.     OSStatus                    status = noErr;
  4510.  
  4511. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMLock");
  4512.  
  4513.     // Get our internal data.
  4514.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  4515.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  4516.  
  4517.     // Set pending command.
  4518.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAsynchCommandParams;
  4519.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  4520.  
  4521.     // Get pointer to link registers.
  4522.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4523.  
  4524.     // Check if generation is up to date.
  4525.     if ((!(pLynxFWIMData->generationValid)) ||
  4526.         (pFWIMAsynchCommandParams->generation != pLynxFWIMData->generation))
  4527.     {
  4528.         status = busReconfiguredErr;
  4529.     }
  4530.  
  4531.     // Set a timeout timer.
  4532.     if (status == noErr)
  4533.     {
  4534.         timeoutAbsolute =
  4535.             AddAbsoluteToAbsolute (UpTime (),
  4536.                                    DurationToAbsolute (pFWIMAsynchCommandParams->timeout));
  4537.         status = SetInterruptTimer
  4538.                     (&timeoutAbsolute, LynxFWIMLockRequestTimeoutHandler,
  4539.                      pFWIMAsynchCommandParams,
  4540.                      &(pLynxFWIMData->requestTimeoutTimerID));
  4541.         if (status == noErr)
  4542.             pLynxFWIMData->requestTimeoutTimerSet = true;
  4543.     }
  4544.  
  4545.     // send lock request.
  4546.     if (status == noErr)
  4547.     {
  4548.         pLynxFWIMData->transactionLabel =
  4549.             (pLynxFWIMData->transactionLabel + 1) & 0x3F;
  4550.         pLynxFWIMData->tCode = kFWTCodeLock;
  4551.         
  4552.         // Prepare packet control header for block transaction.
  4553.         data1 = pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationID;
  4554.         data1 |= (pLynxFWIMData->transactionLabel << kFWAsynchTLabelPhase);
  4555.         data1 |= (kFWAsynchNew << kFWAsynchRtPhase);
  4556.         data1 |= (kFWTCodeLock << kFWPacketTCodePhase);
  4557.  
  4558.         // our ID and the target address.
  4559.         sourceID = EndianSwap32Bit (pLynxRegs->busNumberNodeNumber);
  4560.         data2 = sourceID | (pFWIMAsynchCommandParams->addressHi & kFWAsynchDestinationOffsetHigh);
  4561.         data3 = pFWIMAsynchCommandParams->addressLo;
  4562.  
  4563.         // request length and extended tCode.
  4564.         data4 = pFWIMAsynchCommandParams->length << kFWAsynchDataLengthPhase;
  4565.         data4 |= 
  4566.             (pFWIMAsynchCommandParams->extendedTCode & kFWAsynchExtendedTCode) <<
  4567.             kFWAsynchExtendedTCodePhase;
  4568.  
  4569.         LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchCommandParams->speed, 4, data1, data2, data3, data4,
  4570.                          pFWIMAsynchCommandParams->length,
  4571.                          (UInt32 *) pFWIMAsynchCommandParams->buffer);
  4572.     }
  4573.  
  4574.     // Complete command on error.
  4575.     if (status != noErr)
  4576.     {
  4577.         pLynxFWIMData->pPendingFWIMCommand = nil;
  4578.         status = FWIMCommandIsComplete
  4579.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  4580.                      status);
  4581.     }
  4582.  
  4583.     // Return command acceptance.
  4584.     //zzz what if we call FWIMCommandIsComplete before returning this???
  4585.     //zzz well, it still works, but will it always?
  4586.     //zzz actually, when we switch to the dispatch table, each routine can return
  4587.     //zzz the appropriate acceptance, so don't worry about it for now.
  4588.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  4589.  
  4590.     return (status);
  4591. }
  4592.  
  4593.  
  4594. ////////////////////////////////////////////////////////////////////////////////
  4595. //
  4596. // LynxFWIMLockResponse
  4597. //
  4598. //   This proc sends a lock response packet.
  4599. //zzz should be set up to get acknowledgement
  4600. //
  4601.  
  4602. static OSStatus    LynxFWIMLockResponse(
  4603.     FWIMAsynchResponseCommandParamsPtr
  4604.                                 pFWIMAsynchResponseCommandParams,
  4605.     UInt32                        *pCommandAcceptance)
  4606. {
  4607.     FWIMCommandParamsPtr        pFWIMCommandParams;
  4608.     LynxFWIMDataPtr                pLynxFWIMData; 
  4609.     LynxRegistersPtr            pLynxRegs;
  4610.     UInt32                        data1, data2, data4;
  4611.     UInt32                        sourceID;
  4612.     UInt32                        transactionLabel;
  4613.     UInt32                        responseCode;
  4614.     OSStatus                    status = noErr;
  4615.  
  4616.     // Get our internal data.
  4617.     pFWIMCommandParams = &(pFWIMAsynchResponseCommandParams->fwimCommandParams);
  4618.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  4619.  
  4620.     // Set pending command.
  4621.     pLynxFWIMData->pPendingFWIMResponseCommand =
  4622.         (FWIMCommandParamsPtr) pFWIMAsynchResponseCommandParams;
  4623.  
  4624.     // Get pointer to link registers.
  4625.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  4626.  
  4627.     // already has bit alignment we'll need later...
  4628.     sourceID = EndianSwap32Bit (pLynxRegs->busNumberNodeNumber);//zzz read out of FWIM data
  4629.     
  4630.     // Check if generation is up to date.
  4631.     if ((!(pLynxFWIMData->generationValid)) ||
  4632.         (pFWIMAsynchResponseCommandParams->generation != pLynxFWIMData->generation))
  4633.     {
  4634.         status = busReconfiguredErr;
  4635.     }
  4636.  
  4637.     // Write lock response to ATF.
  4638.     if (status == noErr)
  4639.     {
  4640.         // Compute transaction label and response code.
  4641.         transactionLabel = (pFWIMAsynchResponseCommandParams->transactionDescriptor &
  4642.                             kFWTransactionDescriptorTLabel) >>
  4643.                            kFWTransactionDescriptorTLabelPhase;
  4644.         responseCode = (pFWIMAsynchResponseCommandParams->responseDataHi &
  4645.                         kFWResponseDataRCode) >>
  4646.                        kFWResponseDataRCodePhase;
  4647.  
  4648.         // packet control header goes in quad 1
  4649.         data1 = pFWIMAsynchResponseCommandParams->destinationID << kFWAsynchSourceIDPhase;
  4650.         data1 |= transactionLabel << kFWAsynchTLabelPhase;
  4651.         data1 |= kFWAsynchNew << kFWAsynchRtPhase;
  4652.         data1 |= kFWTCodeLockResponse << kFWPacketTCodePhase;
  4653.  
  4654.         // packet destination node ID and response code go in quad 2
  4655.         data2 = sourceID;
  4656.         data2 |= responseCode << kFWAsynchRCodePhase;
  4657.  
  4658.         data4 = pFWIMAsynchResponseCommandParams->length << kFWAsynchDataLengthPhase;
  4659.         data4 |= 
  4660.             (pFWIMAsynchResponseCommandParams->extendedTCode & kFWAsynchExtendedTCode) <<
  4661.             kFWAsynchExtendedTCodePhase;
  4662.  
  4663.         LynxFWIMWriteATF(pLynxFWIMData, kLynxDMA_XMT, pFWIMAsynchResponseCommandParams->speed, 4, data1, data2, 0, data4, pFWIMAsynchResponseCommandParams->length, (UInt32 *) pFWIMAsynchResponseCommandParams->buffer);
  4664.     }
  4665.  
  4666.     // Complete command on error.
  4667.     //zzz assume success for now.  should check ack code for success.
  4668. //zzz    if (status != noErr)
  4669.     {
  4670.         pLynxFWIMData->pPendingFWIMResponseCommand = nil;
  4671.         status = FWIMCommandIsComplete
  4672.                     (pFWIMAsynchResponseCommandParams->fwimCommandParams.fwimCommandID,
  4673.                      status);
  4674.     }
  4675.  
  4676.     // Return command acceptance.
  4677.     //zzz what if we call FWIMCommandIsComplete before returning this???
  4678.     //zzz well, it still works, but will it always?
  4679.     //zzz actually, when we switch to the dispatch table, each routine can return
  4680.     //zzz the appropriate acceptance, so don't worry about it for now.
  4681.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  4682.  
  4683.     return (status);
  4684. }
  4685.  
  4686.  
  4687. ////////////////////////////////////////////////////////////////////////////////
  4688. //
  4689. // LynxFWIMIsCompilableDCLProgram
  4690. //
  4691. //   This routine determines if the given DCL program is compilable.
  4692. //zzz a table and range check may be faster.
  4693. //zzz should do better checking.
  4694. //zzz maybe we should make this determination in a first pass compilation.
  4695. //
  4696.  
  4697. static Boolean    LynxFWIMIsCompilableDCLProgram(
  4698.     DCLProgramID                dclProgramID)
  4699. {
  4700.     DCLCommandPtr                pDCLCommand;
  4701.     Boolean                        isCompilable = true;
  4702.     UInt32                        opcode;
  4703.     OSStatus                    status = noErr;
  4704.     
  4705.     // Get first DCL in program.
  4706.     status = FWGetDCLProgramStart (dclProgramID, &pDCLCommand);
  4707.     if (status != noErr)
  4708.         isCompilable = false;
  4709.  
  4710.     // Check each DCL in program.
  4711.     while ((isCompilable) && (pDCLCommand != nil))
  4712.     {
  4713.         opcode = pDCLCommand->opcode;
  4714.         opcode &= ~kFWDCLOpDynamicFlag;  // We can compile dynamic opcodes.
  4715.         switch (opcode)
  4716.         {
  4717.             case kDCLReceivePacketStartOp :
  4718.                 break;
  4719.  
  4720.             case kDCLReceivePacketOp :
  4721.                 break;
  4722.  
  4723.             case kDCLSendPacketStartOp :
  4724.                 break;
  4725.  
  4726.             case kDCLSendPacketWithHeaderStartOp :
  4727.                 break;
  4728.  
  4729.             case kDCLSendPacketOp :
  4730.                 break;
  4731.  
  4732.             case kDCLCallProcOp :
  4733.                 break;
  4734.  
  4735.             case kDCLJumpOp :
  4736.                 break;
  4737.  
  4738.             case kDCLLabelOp :
  4739.                 break;
  4740.  
  4741.             case kDCLSetTagSyncBitsOp :
  4742.                 break;
  4743.  
  4744.             case kDCLUpdateDCLListOp :
  4745.                 break;
  4746.  
  4747.             case kDCLTimeStampOp :
  4748.                 break;
  4749.  
  4750.             default :
  4751.                 isCompilable = false;
  4752.                 break;
  4753.         }
  4754.         
  4755.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  4756.     }
  4757.  
  4758.     return (isCompilable);
  4759. }
  4760.  
  4761.  
  4762. ////////////////////////////////////////////////////////////////////////////////
  4763. //
  4764. // LynxFWIMPrepareDCLProgramMemory
  4765. //
  4766. //   This routine prepares all buffers used within a DCL program for physical
  4767. //   I/O, and determines the physical addresses.  dclList is the entire program.
  4768. //
  4769.  
  4770. static OSStatus LynxFWIMPrepareDCLProgramMemory(
  4771.     LynxDCLCompilerEngineDataPtr
  4772.                                 pLynxDCLCompilerEngineData,
  4773.     DCLCommandPtr                dclList,
  4774.     UInt32                        dclListLength)
  4775. {
  4776.     DCLCommandPtr                pDCL;
  4777.     DCLTransferPacketPtr        pDCLTransferPacket;
  4778.     IOPreparationTable            *ioPrep;
  4779.     PhysicalAddress                *physAddrs;                // should be PhysicalMappingTablePtr
  4780.     AddressRangeTablePtr        rangeTable;
  4781.     UInt32                        pageSize, pageShift, pageMask, tmp;
  4782.     UInt32                        pageCount, bufferCount;
  4783.     AbsoluteTime                timeNow;
  4784.     OSStatus                    status = noErr;
  4785.     
  4786.     ioPrep = &pLynxDCLCompilerEngineData->ioPrep;
  4787.     pageSize = GetLogicalPageSize ();
  4788.     pageShift = 0;
  4789.     for (tmp = pageSize; tmp = tmp >> 1; pageShift++);            // Sorry...
  4790.     pageMask = ~(pageSize - 1);
  4791.     
  4792.     // This is gross too.  Make sure we don't use stale data in lookups.
  4793.     timeNow = UpTime ();
  4794.     pLynxDCLCompilerEngineData->engineGeneration = AbsoluteToDuration (timeNow);
  4795.     
  4796.     // We will need to allocate a page table.  We don't know how big it needs
  4797.     // to be, but we can wait until just before we PrepareMemoryForIO to do
  4798.     // the allocation (by then we'll know)
  4799.     
  4800.     // We need to allocate a range/length table.  We fill that in before we
  4801.     // call PrepareMemoryForIO, and it has to be linear, so we have to allocate
  4802.     // it all at once.  We need one entry for each buffer in the program.
  4803.     // That's why we take a parameter indicating the program length.
  4804.     // Note if we ever allow scatter/gather buffers in a DCL program, this
  4805.     // will have to change.
  4806.     
  4807.     // We assumed (in LynxFWIMCompileDCLProgram) that each DCL contained a buffer.
  4808.     // Some of them are branches, etc, so an optimization would be to count more
  4809.     // precisely and save a little memory.
  4810.     
  4811.     // Allocate space for rangeTable
  4812.     if (status == noErr)
  4813.     {        
  4814.         rangeTable = (AddressRangeTablePtr)
  4815.             PoolAllocateResident (dclListLength * sizeof (AddressRange), false);
  4816.         if (!rangeTable) status = memFullErr;
  4817.         ioPrep->rangeInfo.multipleRanges.entryCount = 0;
  4818.         // move this below, use local copy
  4819.         ioPrep->rangeInfo.multipleRanges.rangeTable = rangeTable;
  4820.     }    
  4821.  
  4822.     // Gather information about buffers/pointers
  4823.     if (status == noErr)
  4824.     {
  4825.         pDCL = dclList;
  4826.         bufferCount = 0;        // shadow of ioPrep->rangeInfo.multipleRanges.entryCount
  4827.         pageCount = 0;            // count page table size we will need to allocate
  4828.         
  4829.         while (pDCL != nil)
  4830.         {
  4831.             switch (pDCL->opcode & ~kFWDCLOpFlagMask)
  4832.             {
  4833.                 case kDCLReceivePacketStartOp :
  4834.                 case kDCLReceivePacketOp :
  4835.                 case kDCLSendPacketStartOp :
  4836.                 case kDCLSendPacketWithHeaderStartOp :
  4837.                 case kDCLSendPacketOp :
  4838.  
  4839.                     pDCLTransferPacket = (DCLTransferPacketPtr) pDCL;
  4840.                     rangeTable[bufferCount].base = (void *) pDCLTransferPacket->buffer;
  4841.                     rangeTable[bufferCount].length = pDCLTransferPacket->size;
  4842.                     bufferCount++;
  4843.                     
  4844.                     // buffer + size - 1 is addr of last byte in buffer.
  4845.                     // shift that right by pageShift to get page index of end.
  4846.                     // subtract first page index and add one to get total page count.
  4847.                     
  4848.                     pageCount += // (last page - first page) + 1
  4849.                         ((((((UInt32) (pDCLTransferPacket->buffer)) + pDCLTransferPacket->size) - 1) >> pageShift) -
  4850.                             (((UInt32) (pDCLTransferPacket->buffer)) >> pageShift) + 1);
  4851.                     break;
  4852.                     
  4853.                 default : //No buffer or pointer - nothing to do
  4854.                     break;
  4855.             }
  4856.  
  4857.             pDCL = pDCL->pNextDCLCommand;
  4858.         }
  4859.     }
  4860.  
  4861.     // Allocate space for page table
  4862.     if (status == noErr)
  4863.     {
  4864.         physAddrs = PoolAllocateResident (pageCount * sizeof (PhysicalAddress), false);
  4865.         if (!physAddrs)
  4866.         {
  4867.             status = memFullErr;
  4868.             PoolDeallocate ((Ptr) rangeTable);
  4869.         }
  4870.         pLynxDCLCompilerEngineData->physAddrs = physAddrs;
  4871.     }
  4872.     
  4873.     // Prepare memory for I/O
  4874.     if (status == noErr)
  4875.     {
  4876.         ioPrep->options = kIOMultipleRanges | kIOLogicalRanges |
  4877.                           kIOIsInput | kIOIsOutput;
  4878.         ioPrep->addressSpace = kCurrentAddressSpaceID;            // default
  4879.         ioPrep->granularity = 0;                                // do it all now
  4880.         ioPrep->firstPrepared = 0;
  4881.         ioPrep->mappingEntryCount = pageCount;                    // we counted exactly
  4882.         ioPrep->logicalMapping = 0;
  4883.         ioPrep->physicalMapping = physAddrs;                    // return list of phys addrs
  4884.         ioPrep->rangeInfo.multipleRanges.entryCount = bufferCount;
  4885.  
  4886.         // CheckpointIO is in _LynxFWIMReleaseIsochPort
  4887.         status = PrepareMemoryForIO (ioPrep);
  4888.         if (status != noErr)
  4889.         {
  4890.             ioPrep->mappingEntryCount = -1;                        // prevents CheckpointIO, kind of a hack
  4891.             PoolDeallocate ((Ptr) rangeTable);
  4892.             PoolDeallocate ((Ptr) physAddrs);
  4893.  
  4894.             sprintf (debugStr, "DCL data PrepMemIO status %ld    page count %ld",
  4895.                      (long) status,
  4896.                      (long) pageCount);
  4897.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  4898.         }
  4899.     }
  4900.     
  4901.     return status;
  4902. }
  4903.  
  4904.  
  4905. ////////////////////////////////////////////////////////////////////////////////
  4906. //
  4907. // LynxFWIMDMapBufferToPhysical
  4908. //
  4909. //   This routine looks up physical addresses for buffers/pointers.
  4910. //     Fills in the passed page table, returns page count (0 if not found)
  4911.  
  4912. static UInt32 LynxFWIMDataMapToPhysical (
  4913.     LynxDCLCompilerEngineDataPtr
  4914.                                 pLynxDCLCompilerEngineData,
  4915.     Ptr                            pBuffer,
  4916.     UInt32                        size,
  4917.     PhysicalMappingTablePtr        returnTable)
  4918. {
  4919.     UInt32                        pageCount = 0, lookCount = 0;
  4920.     static UInt32                rangeLook = 0, pageLook = 0;
  4921.     static UInt32                pageSize = 0, pageShift = 0;
  4922.     static UInt32                cacheEngineGeneration = 0;
  4923.     IOPreparationTable            *ioPrep = &pLynxDCLCompilerEngineData->ioPrep;
  4924.     AddressRangeTablePtr        try;
  4925.     if (!pageSize)
  4926.     {
  4927.         UInt32 tmp;
  4928.         pageSize = GetLogicalPageSize ();
  4929.         for (tmp = pageSize; tmp = tmp >> 1; pageShift++);            // Sorry...
  4930.     }
  4931.     
  4932.     // Look up phys addrs in our prepared table
  4933.     // Return in provided page table
  4934.     
  4935.     // Start lookup from last known point, if we build in order, lookup is fast
  4936.     // Strictly speaking, rangeLook and pageLook should be static to the
  4937.     // engine data, not the whole FWIM, but I don't think we can compile more
  4938.     // than one DCL program at a time anyway.
  4939.     //
  4940.     // Perhaps more importantly, they should be reset if we've rebuilt the ioPrep,
  4941.     // because they may be off the end or otherwise inaccurate.
  4942.     //
  4943.     // I'm not sure this (optimization) works - it still seems sluggish.
  4944.     
  4945.     if (cacheEngineGeneration != pLynxDCLCompilerEngineData->engineGeneration)
  4946.     {
  4947.         cacheEngineGeneration = pLynxDCLCompilerEngineData->engineGeneration;
  4948.         rangeLook = 0;
  4949.         pageLook = 0;
  4950.     }
  4951.     
  4952.     // Repeat until we find it or run out of places to look
  4953.     
  4954.     while ((lookCount < ioPrep->rangeInfo.multipleRanges.entryCount) && (!pageCount))
  4955.     {
  4956.         try = &ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook];
  4957.         
  4958.         // pageCount is number of physAddr entries used by this range
  4959.         // either copy them (found) or skip over them (not found)
  4960.         
  4961.         pageCount = 1 + (((UInt32) try->base + try->length - 1) >> pageShift) -
  4962.                          ((UInt32) try->base >> pageShift);
  4963.                          
  4964.         // require exact match
  4965.         if ((void *) pBuffer == ioPrep->rangeInfo.multipleRanges.rangeTable[rangeLook].base)
  4966.         {
  4967.             // Found pages we want.  Copy page table.
  4968.             BlockCopy (&ioPrep->physicalMapping[pageLook],
  4969.                        returnTable,
  4970.                        pageCount * sizeof (PhysicalAddress));
  4971.             pageLook += pageCount;
  4972.         }
  4973.         else
  4974.         {
  4975.             // These aren't the pages we're looking for.  Skip forward.
  4976.             pageLook += pageCount;
  4977.             pageCount = 0;
  4978.         }
  4979.         
  4980.         lookCount++;
  4981.         rangeLook++;
  4982.         if (rangeLook == ioPrep->rangeInfo.multipleRanges.entryCount)
  4983.         {
  4984.             rangeLook = 0;
  4985.             pageLook = 0;
  4986.         }
  4987.     }
  4988.     
  4989.     if (!pageCount)
  4990.         FWDebugStr ((ConstStr255Param) "\pFailed to find buffer!");
  4991.     
  4992.     return pageCount;
  4993. }
  4994.  
  4995.  
  4996. ////////////////////////////////////////////////////////////////////////////////
  4997. //
  4998. // LynxFWIMCompileDCLProgram
  4999. //
  5000. //   This routine compiles the given DCL program into a PCL program.
  5001. //zzz rename this
  5002. //zzz need to convert data endianess (really?  I think Lynx DMA does that)
  5003. //zzz need to set proper speed.
  5004. //
  5005.  
  5006. static OSStatus LynxFWIMCompileDCLProgram(
  5007.     LynxFWIMDataPtr                pLynxFWIMData,
  5008.     DCLProgramID                dclProgramID,
  5009.     UInt32                        pclChannelNum,
  5010.     UInt32                        channelNum,
  5011.     UInt32                        speed)
  5012. {
  5013.     LynxPCLBuildStatePtr        pLynxPCLBuildState = nil;
  5014.     LynxDCLCompilerEngineDataPtr
  5015.                                 pLynxDCLCompilerEngineData = nil;
  5016.     DCLCommandPtr                pDCLCommand,
  5017.                                 dclList;
  5018.     DCLLabel                    waitLoopDCLLabel,
  5019.                                 transmitDCLLabel;
  5020.     DCLCommand                    waitLoopDCLCommand;
  5021.     LynxPCLPtr                    pStartPCL;
  5022.     UInt32                        startEvent,
  5023.                                 startEventState,
  5024.                                 startEventStateMask;
  5025.     UInt32                        dclListLength;
  5026.     OSStatus                    status = noErr;
  5027.  
  5028.     // Create DCL engine data record.
  5029.     pLynxDCLCompilerEngineData = (LynxDCLCompilerEngineDataPtr)
  5030.         PoolAllocateResident (sizeof (LynxDCLCompilerEngineData), true);
  5031.     if (pLynxDCLCompilerEngineData == nil)
  5032.         status = memFullErr;
  5033.         
  5034.     // Initialize interrupt queue.
  5035.     if (status == noErr)
  5036.         pLynxFWIMData->pDCLInterruptTail[pclChannelNum] = nil;
  5037.         
  5038.     // Set compiler notification proc.
  5039.     if (status == noErr)
  5040.     {
  5041.         status = FWSetDCLProgramCompilerNotificationProc
  5042.                     (dclProgramID, LynxFWIMDCLCompilerNotification);
  5043.     }
  5044.  
  5045.     // Get DCL list from program.
  5046.     //zzz should check for error.
  5047.     if (status == noErr)
  5048.     status = FWGetDCLProgramStart (dclProgramID, &dclList);
  5049.  
  5050.     // Clear compiler data in all DCLs, and count them.
  5051.     if (status == noErr)
  5052.     {
  5053.         pDCLCommand = dclList;
  5054.         dclListLength = 0;
  5055.         while (pDCLCommand != nil)
  5056.         {
  5057.             pDCLCommand->compilerData = nil;
  5058.             pDCLCommand = pDCLCommand->pNextDCLCommand;
  5059.             dclListLength++;
  5060.         }
  5061.     }
  5062.  
  5063.     // The plan is to, before compiling, scan the program to locate all data
  5064.     // buffers.  Then we'll prepare VM mappings for them all at once.  Then
  5065.     // during compilation we can look up the logical->physical mappings.
  5066.     //
  5067.     // A complication is that we may receive notification that a running
  5068.     // program has had its buffers changed.  We get a list of changes.  In
  5069.     // that case we need to prepare the new buffers for DMA and change the
  5070.     // pointers in the PCLs, possibly expanding PCLs if there are more
  5071.     // page crossings than before.  (or maybe not)
  5072.     //
  5073.     // When we update buffers, some may be unchanged, so we can't clear the
  5074.     // original PrepareMemoryForIO.  Buffers can be updated repeatedly, and
  5075.     // we could pile up unlimited ioPrep structures.  So we use a brute-force
  5076.     // solution (NYI) and redo the *entire* ioPrep, not just the changed buffers.
  5077.     // Then we can free (CheckpointIO) the original one, and all live buffers
  5078.     // are still covered.  (There is room for optimizations in that process.)
  5079.     //
  5080.     // The first time we prepare memory, we have the luxury that the program
  5081.     // is not running.  When we do updates, the program *is* running.  But maybe
  5082.     // we can use the same code both times, somehow.
  5083.     
  5084.     if (status == noErr)
  5085.         status = LynxFWIMPrepareDCLProgramMemory (pLynxDCLCompilerEngineData,
  5086.                                                   dclList,
  5087.                                                   dclListLength);
  5088.  
  5089.     // Start our PCL program.
  5090.     if (status == noErr)
  5091.     {
  5092.         status = LynxFWIMPCLStart (pLynxFWIMData, &pLynxPCLBuildState, &pStartPCL);
  5093.         
  5094.         if (status == noErr)
  5095.         {
  5096.             pLynxPCLBuildState->pLynxDCLCompilerEngineData = pLynxDCLCompilerEngineData;
  5097.             pLynxPCLBuildState->pclChannelNum = pclChannelNum;
  5098.             pLynxPCLBuildState->isochChannelNum = channelNum;
  5099.             
  5100.             // When we called PCLStart we allocated the first pool of PCLs (physical memory)
  5101.             // make a note of where the isoch packet header is, we'll use that for this program
  5102.  
  5103.             // This is the header's true location and contents.
  5104.             pLynxDCLCompilerEngineData->isochPacketHeaderPtr =
  5105.                 &(pLynxPCLBuildState->pLynxPCLPoolDataList->isochPacketHeader);
  5106.             *(pLynxDCLCompilerEngineData->isochPacketHeaderPtr) =
  5107.                 (kFWTCodeIsochronousBlock << kFWIsochTCodePhase) |
  5108.                 (channelNum << kFWIsochChanNumPhase);
  5109.                 
  5110.             // make note of the physical address
  5111.             pLynxDCLCompilerEngineData->isochPacketHeaderPhys =
  5112.                 pLynxPCLBuildState->pLynxPCLPoolDataList->isochPacketHeaderPhys;
  5113.  
  5114. #ifdef LynxVMDebug
  5115.             if (((Ptr) (pLynxDCLCompilerEngineData->isochPacketHeaderPtr)) !=
  5116.                 ((Ptr) (pLynxDCLCompilerEngineData->isochPacketHeaderPhys)))
  5117.             {
  5118.                 sprintf (debugStr, "Isoch header PTR (A)  logical %08lx != physical %08lx",
  5119.                          (long) pLynxDCLCompilerEngineData->isochPacketHeaderPtr,
  5120.                          (long) pLynxDCLCompilerEngineData->isochPacketHeaderPhys);
  5121.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  5122.             }
  5123. #endif
  5124.         }
  5125.     }
  5126.     
  5127.     // Check if there's a start event for the cycle count.
  5128.     if (status == noErr)
  5129.     {
  5130.         status = FWGetDCLProgramStartEvent
  5131.                     (dclProgramID, &startEvent, &startEventState, &startEventStateMask);
  5132.     }
  5133.     if ((status == noErr) && (startEvent == kFWDCLCycleEvent))
  5134.     {//zzz need to deal with mask including upper 16 bits
  5135.         // Create some DCLs to wait for cycle event.
  5136.         waitLoopDCLLabel.pNextDCLCommand = &waitLoopDCLCommand;
  5137.         waitLoopDCLLabel.compilerData = nil;
  5138.         waitLoopDCLLabel.opcode = kDCLLabelOp;
  5139.     
  5140.         waitLoopDCLCommand.pNextDCLCommand = (DCLCommandPtr) &transmitDCLLabel;
  5141.         waitLoopDCLCommand.compilerData = nil;
  5142.         waitLoopDCLCommand.opcode = kDCLInvalidOp;
  5143.  
  5144.         transmitDCLLabel.pNextDCLCommand = dclList;
  5145.         transmitDCLLabel.compilerData = nil;
  5146.         transmitDCLLabel.opcode = kDCLLabelOp;
  5147.  
  5148.         // Add wait loop label.
  5149.         status = 
  5150.             LynxFWIMAddLabelDCL (pLynxPCLBuildState, (DCLCommandPtr) &waitLoopDCLLabel);
  5151.  
  5152.         // Add a wait for cycle count commands.
  5153.         // We must set up to start filling the cycle before the cycle we want the packet
  5154.         // to go out on.
  5155.         //zzz setting a compare for startEventState - (1 << 12) will only work right
  5156.         //zzz when bit 12 is set in the mask.
  5157.         if (status == noErr)
  5158.         {
  5159.             //This address is already physical, no translation needed
  5160.             status =
  5161.                 LynxFWIMPCLLoadTemp (pLynxPCLBuildState,
  5162.                                      (Ptr) &(pLynxFWIMData->pLynxRegisters->cycleTimer));
  5163.         }
  5164.         if (status == noErr)
  5165.         {
  5166.             status = LynxFWIMPCLCompareTemp16WithMask (pLynxPCLBuildState,
  5167.                                                        startEventState - (1 << 12),
  5168.                                                        startEventStateMask);
  5169.         }
  5170.         if (status == noErr)
  5171.             status = LynxFWIMPCLBranchIfEqual (pLynxPCLBuildState, &transmitDCLLabel);
  5172.         if (status == noErr)
  5173.             status = LynxFWIMPCLJump (pLynxPCLBuildState, &waitLoopDCLLabel, nil);
  5174.  
  5175.         // Add transmit label.
  5176.         if (status == noErr)
  5177.         {
  5178.             status = LynxFWIMAddLabelDCL (pLynxPCLBuildState,
  5179.                                           (DCLCommandPtr) &transmitDCLLabel);
  5180.             
  5181.             // Set ready register to 1 after we exit the wait loop.
  5182.             // We'll stop transmitting if we find ready has been zeroed.
  5183.             
  5184.             status = LynxFWIMPCLStore1 (pLynxPCLBuildState,
  5185.                      (Ptr) &(pLynxFWIMData->pLynxRegisters->dmaChannel[kIsochTransmitDMA].ready));
  5186.         }
  5187.     }
  5188.  
  5189.     // Process all DCLs.
  5190.     pDCLCommand = dclList;
  5191.     while ((pDCLCommand != nil) && (status == noErr))
  5192.     {
  5193.         status = LynxFWIMAddDCL (pLynxPCLBuildState, pDCLCommand);
  5194.         pDCLCommand = pDCLCommand->pNextDCLCommand;
  5195.     }
  5196.     
  5197.     // Fill in DCL engine data record.
  5198.     if (status == noErr)
  5199.     {
  5200.         pLynxDCLCompilerEngineData->pStartPCL = pStartPCL;
  5201.         pLynxDCLCompilerEngineData->pLynxPCLPoolDataList =
  5202.             pLynxPCLBuildState->pLynxPCLPoolDataList;
  5203.         pLynxDCLCompilerEngineData->pLynxFWIMData = pLynxFWIMData;
  5204.     }
  5205.     
  5206.     // Save engine data.
  5207.     if (status == noErr)
  5208.     {
  5209.         status = FWSetDCLProgramEngineData (dclProgramID,
  5210.                                             (UInt32) pLynxDCLCompilerEngineData);
  5211.     }
  5212.     
  5213.     // Clean up on error.
  5214.     if (status != noErr)
  5215.     {
  5216.         // Deallocate PCL pools.
  5217.         if (pLynxPCLBuildState != nil)
  5218.             if (pLynxPCLBuildState->pLynxPCLPoolDataList != nil)
  5219.                 LynxFWIMDeallocatePCLPools (pLynxPCLBuildState->pLynxPCLPoolDataList);
  5220.  
  5221.         // Deallocate engine data.
  5222.         if (pLynxDCLCompilerEngineData != nil)
  5223.             PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData);
  5224.     }
  5225.  
  5226.     // Clean up.
  5227.     if (pLynxPCLBuildState != nil)
  5228.         PoolDeallocate ((Ptr) pLynxPCLBuildState);
  5229.  
  5230.     return (status);
  5231. }
  5232.  
  5233.  
  5234. ////////////////////////////////////////////////////////////////////////////////
  5235. //
  5236. // LynxFWIMAddDCL
  5237. //
  5238. //   This proc adds the given DCL.
  5239. //
  5240.  
  5241. static OSStatus LynxFWIMAddDCL(
  5242.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5243.     DCLCommandPtr                pDCLCommand)
  5244. {
  5245.     UInt32                        opcode;
  5246.     OSStatus                    status = noErr;
  5247.  
  5248.     // Dispatch off of opcode.
  5249.     opcode = pDCLCommand->opcode & ~kFWDCLOpFlagMask;
  5250.     switch (opcode)
  5251.     {
  5252.         case kDCLReceivePacketStartOp :
  5253.             if (status == noErr)
  5254.                 status = LynxFWIMAddReceivePacketStartDCL (pLynxPCLBuildState, pDCLCommand);
  5255.             break;
  5256.             
  5257.         case kDCLReceivePacketOp :
  5258.             if (status == noErr)
  5259.                 status = LynxFWIMAddReceivePacketDCL (pLynxPCLBuildState, pDCLCommand);
  5260.             break;
  5261.             
  5262.         case kDCLSendPacketStartOp :
  5263.             if (status == noErr)
  5264.                 status = LynxFWIMAddSendPacketStartDCL (pLynxPCLBuildState, pDCLCommand);
  5265.             break;
  5266.             
  5267.         case kDCLSendPacketWithHeaderStartOp :
  5268.             if (status == noErr)
  5269.             {
  5270.                 status = LynxFWIMAddSendPacketWithHeaderStartDCL
  5271.                             (pLynxPCLBuildState, pDCLCommand);
  5272.             }
  5273.             break;
  5274.             
  5275.         case kDCLSendPacketOp :
  5276.             status = LynxFWIMAddSendPacketDCL (pLynxPCLBuildState, pDCLCommand);
  5277.             break;
  5278.  
  5279.         case kDCLCallProcOp :
  5280.             status = LynxFWIMAddCallProcDCL (pLynxPCLBuildState, pDCLCommand);
  5281.             break;
  5282.  
  5283.         case kDCLJumpOp :
  5284.             status = LynxFWIMAddJumpDCL (pLynxPCLBuildState, pDCLCommand);
  5285.             break;
  5286.  
  5287.         case kDCLLabelOp :
  5288.             status = LynxFWIMAddLabelDCL (pLynxPCLBuildState, pDCLCommand);
  5289.             break;
  5290.  
  5291.         case kDCLSetTagSyncBitsOp :
  5292.             status = LynxFWIMAddSetTagSyncBitsDCL (pLynxPCLBuildState, pDCLCommand);
  5293.             break;
  5294.  
  5295.         case kDCLUpdateDCLListOp :
  5296.             status = LynxFWIMUpdateDCLListDCL (pLynxPCLBuildState, pDCLCommand);
  5297.             break;
  5298.  
  5299.         case kDCLTimeStampOp :
  5300.             status = LynxFWIMTimeStampDCL (pLynxPCLBuildState, pDCLCommand);
  5301.             break;
  5302.  
  5303.         default : //zzz what can we do?
  5304.             break;
  5305.     }
  5306.     
  5307.     return (status);
  5308. }
  5309.  
  5310.  
  5311. ////////////////////////////////////////////////////////////////////////////////
  5312. //
  5313. // LynxFWIMAddReceivePacketStartDCL
  5314. //
  5315. //   This proc adds a receive packet start DCL.
  5316. //zzz need to be able to specify speed.
  5317. //
  5318.  
  5319. static OSStatus LynxFWIMAddReceivePacketStartDCL(
  5320.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5321.     DCLCommandPtr                pDCLCommand)
  5322. {
  5323.     DCLTransferPacketPtr        pDCLTransferPacket;
  5324.     OSStatus                    status = noErr;
  5325.  
  5326.     // Recast DCL command.
  5327.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  5328.     
  5329.     // Start new receive PCL.
  5330.     status = LynxFWIMPCLNewIsochReceive
  5331.                 (pLynxPCLBuildState,
  5332.                  (LynxPCLPtr *) &(pDCLTransferPacket->compilerData),
  5333.                  (UInt32) pDCLTransferPacket,
  5334.                  kLynxDMA100mbps);
  5335.  
  5336.     // Add payload buffer.
  5337.     if (status == noErr)
  5338.     {
  5339.         status = LynxFWIMPCLAddTransferBuffer
  5340.                     (pLynxPCLBuildState,
  5341.                      pDCLTransferPacket->buffer,
  5342.                      pDCLTransferPacket->size,
  5343.                      (Ptr *) &(pDCLTransferPacket->compilerData),
  5344.                      kLynxLogicalBuffer);
  5345.     }
  5346.     
  5347.     return (status);
  5348. }
  5349.  
  5350.  
  5351. ////////////////////////////////////////////////////////////////////////////////
  5352. //
  5353. // LynxFWIMAddReceivePacketDCL
  5354. //
  5355. //   This proc adds a receive packet DCL.
  5356. //
  5357.  
  5358. static OSStatus LynxFWIMAddReceivePacketDCL(
  5359.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5360.     DCLCommandPtr                pDCLCommand)
  5361. {
  5362.     DCLTransferPacketPtr        pDCLTransferPacket;
  5363.     OSStatus                    status = noErr;
  5364.  
  5365.     // Recast DCL command.
  5366.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  5367.     
  5368.     // Add payload buffer.
  5369.     if (status == noErr)
  5370.     {
  5371.         status = LynxFWIMPCLAddTransferBuffer
  5372.                     (pLynxPCLBuildState,
  5373.                      pDCLTransferPacket->buffer,
  5374.                      pDCLTransferPacket->size,
  5375.                      (Ptr *) &(pDCLTransferPacket->compilerData),
  5376.                      kLynxLogicalBuffer);
  5377.     }
  5378.     
  5379.     return (status);
  5380. }
  5381.  
  5382.  
  5383. ////////////////////////////////////////////////////////////////////////////////
  5384. //
  5385. // LynxFWIMAddSendPacketStartDCL
  5386. //
  5387. //   This proc adds a send packet start DCL.
  5388. //zzz need to be able to specify speed.
  5389. //
  5390.  
  5391. static OSStatus LynxFWIMAddSendPacketStartDCL(
  5392.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5393.     DCLCommandPtr                pDCLCommand)
  5394. {
  5395.     DCLTransferPacketPtr        pDCLTransferPacket,
  5396.                                 pDCLTransferPacketStart;
  5397.     UInt32                        packetSize;
  5398.     UInt32                        packetHeader,
  5399.                                 *pPacketHeaderStorage;
  5400.     PhysicalAddress                pPacketHeaderStoragePhys;
  5401.     Ptr                            pIsochPacketHeader;
  5402.     OSStatus                    status = noErr;
  5403.  
  5404.     // Recast DCL command.
  5405.     pDCLTransferPacketStart = (DCLTransferPacketPtr) pDCLCommand;
  5406.  
  5407.     // Compute packet size by adding this and all subsequent send packets.
  5408.     packetSize = pDCLTransferPacketStart->size;
  5409.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLTransferPacketStart->pNextDCLCommand;
  5410.     while (pDCLTransferPacket != nil)
  5411.     {
  5412.         if ((pDCLTransferPacket->opcode & ~kFWDCLOpFlagMask) == kDCLSendPacketOp)
  5413.         {
  5414.             packetSize += pDCLTransferPacket->size;
  5415.             pDCLTransferPacket =
  5416.                 (DCLTransferPacketPtr) pDCLTransferPacket->pNextDCLCommand;
  5417.         }
  5418.         else
  5419.         {
  5420.             pDCLTransferPacket = nil;
  5421.         }
  5422.     }
  5423.     
  5424.     // Start new transmit PCL.
  5425.     status = LynxFWIMPCLNewIsochTransmit
  5426.                 (pLynxPCLBuildState,
  5427.                  (LynxPCLPtr *) &(pDCLTransferPacketStart->compilerData),
  5428.                  (UInt32) pDCLTransferPacketStart,
  5429.                  kLynxDMA100mbps);
  5430.  
  5431.     // Create packet header.
  5432.     if (status == noErr)
  5433.         packetHeader = packetSize << kFWIsochDataLengthPhase;
  5434.     
  5435.     // Allocate storage in PCL for header.
  5436.     if (status == noErr)
  5437.     {
  5438.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, &pPacketHeaderStorage);
  5439.         if (status == noErr)
  5440.             *pPacketHeaderStorage = packetHeader;
  5441.         // Now convert it to a physical address
  5442.         // I sure hope this was allocated in pLynxPCLBuildState->pCurrentPCL
  5443.         // Debug check below might not catch that
  5444.         // You know, maybe it would be better to make LynxFWIMPCLAllocateWord just return the
  5445.         // physical address.  I think we always end up converting anyway.  And it will be correct.
  5446.         pPacketHeaderStoragePhys = (PhysicalAddress)
  5447.             ((UInt32) pLynxPCLBuildState->pCurrentPCL->refCon +
  5448.              ((UInt32) pPacketHeaderStorage - (UInt32) pLynxPCLBuildState->pCurrentPCL));
  5449.  
  5450. #ifdef LynxVMDebug
  5451.         if (((Ptr) (pPacketHeaderStorage)) !=
  5452.             ((Ptr) (pPacketHeaderStoragePhys)))
  5453.         {
  5454.             sprintf (debugStr, "Isoch header PTR (C)  logical %08lx != physical %08lx",
  5455.                      (long) pPacketHeaderStorage,
  5456.                      (long) pPacketHeaderStoragePhys);
  5457.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  5458.         }
  5459. #endif
  5460.     }
  5461.     
  5462.     // Add packet size part of header buffer.
  5463.     if (status == noErr)
  5464.     {
  5465.         status = LynxFWIMPCLAddTransferBuffer
  5466.                     (pLynxPCLBuildState,
  5467.                      (Ptr) pPacketHeaderStoragePhys,
  5468.                      2,
  5469.                      (Ptr *) &(pDCLTransferPacketStart->compilerData),
  5470.                      kLynxPhysicalBuffer);
  5471.     }
  5472.  
  5473.     // Add rest of header buffer.
  5474.     if (status == noErr)
  5475.     {
  5476.         pIsochPacketHeader =
  5477.             (Ptr) (pLynxPCLBuildState->pLynxDCLCompilerEngineData->isochPacketHeaderPhys);
  5478.         status = LynxFWIMPCLAddTransferBuffer
  5479.                     (pLynxPCLBuildState,
  5480.                      pIsochPacketHeader + 2,
  5481.                      2,
  5482.                      nil,
  5483.                      kLynxPhysicalBuffer);
  5484.     }
  5485.     
  5486.     // Add payload buffer.
  5487.     if (status == noErr)
  5488.     {
  5489.         status = LynxFWIMPCLAddTransferBuffer (pLynxPCLBuildState,
  5490.                                                pDCLTransferPacketStart->buffer,
  5491.                                                pDCLTransferPacketStart->size,
  5492.                                                nil,
  5493.                                                kLynxLogicalBuffer);
  5494.     }
  5495.     
  5496.     return (status);
  5497. }
  5498.  
  5499.  
  5500. ////////////////////////////////////////////////////////////////////////////////
  5501. //
  5502. // LynxFWIMAddSendPacketWithHeaderStartDCL
  5503. //
  5504. //   This proc adds a send packet with header start DCL.
  5505. //zzz need to be able to specify speed.
  5506. //
  5507.  
  5508. static OSStatus LynxFWIMAddSendPacketWithHeaderStartDCL(
  5509.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5510.     DCLCommandPtr                pDCLCommand)
  5511. {
  5512.     DCLTransferPacketPtr        pDCLTransferPacketStart;
  5513.     OSStatus                    status = noErr;
  5514.  
  5515.     // Recast DCL command.
  5516.     pDCLTransferPacketStart = (DCLTransferPacketPtr) pDCLCommand;
  5517.  
  5518.     // Start new transmit PCL.
  5519.     status = LynxFWIMPCLNewIsochTransmit
  5520.                 (pLynxPCLBuildState,
  5521.                  (LynxPCLPtr *) &(pDCLTransferPacketStart->compilerData),
  5522.                  (UInt32) pDCLTransferPacketStart,
  5523.                  kLynxDMA100mbps);
  5524.  
  5525.     // Add buffer.
  5526.     if (status == noErr)
  5527.     {
  5528.         status = LynxFWIMPCLAddTransferBuffer (pLynxPCLBuildState,
  5529.                                                pDCLTransferPacketStart->buffer,
  5530.                                                pDCLTransferPacketStart->size,
  5531.                                                nil,
  5532.                                                kLynxLogicalBuffer);
  5533.     }
  5534.     
  5535.     return (status);
  5536. }
  5537.  
  5538.  
  5539. ////////////////////////////////////////////////////////////////////////////////
  5540. //
  5541. // LynxFWIMAddSendPacketDCL
  5542. //
  5543. //   This proc adds a send packet DCL.
  5544. //   zzz In case it doesn't get documented anywhere else, the DCL "SendPacket"
  5545. //   actually means send *part* of a packet.  All consecutive SendPackets will
  5546. //   be merged together with the previous SendPacketStart, to form a single packet.
  5547. //   The same is true of ReceivePacket.
  5548. //
  5549.  
  5550. static OSStatus LynxFWIMAddSendPacketDCL(
  5551.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5552.     DCLCommandPtr                pDCLCommand)
  5553. {
  5554.     DCLTransferPacketPtr        pDCLTransferPacket;
  5555.     OSStatus                    status = noErr;
  5556.  
  5557.     // Recast DCL command.
  5558.     pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  5559.     
  5560.     // Add buffer.
  5561.     status = LynxFWIMPCLAddTransferBuffer (pLynxPCLBuildState,
  5562.                                            pDCLTransferPacket->buffer,
  5563.                                            pDCLTransferPacket->size,
  5564.                                            (Ptr *) &(pDCLTransferPacket->compilerData),
  5565.                                            kLynxLogicalBuffer);
  5566.  
  5567.     return (status);
  5568. }
  5569.  
  5570.  
  5571. ////////////////////////////////////////////////////////////////////////////////
  5572. //
  5573. // LynxFWIMAddCallProcDCL
  5574. //
  5575. //   This proc adds a call proc DCL.
  5576. //
  5577.  
  5578. static OSStatus LynxFWIMAddCallProcDCL(
  5579.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5580.     DCLCommandPtr                pDCLCommand)
  5581. {
  5582.     OSStatus                    status = noErr;
  5583.     
  5584.     // Add an interrupt PCL.
  5585.     status = LynxFWIMPCLInterrupt (pLynxPCLBuildState,
  5586.                                    pDCLCommand,
  5587.                                    (Ptr *) &(pDCLCommand->compilerData));
  5588.     
  5589.     return (status);
  5590. }
  5591.  
  5592.  
  5593. ////////////////////////////////////////////////////////////////////////////////
  5594. //
  5595. // LynxFWIMAddJumpDCL
  5596. //
  5597. //   This proc adds a jump DCL.
  5598. //
  5599.  
  5600. static OSStatus LynxFWIMAddJumpDCL(
  5601.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5602.     DCLCommandPtr                pDCLCommand)
  5603. {
  5604.     DCLJumpPtr                    pDCLJump;
  5605.     OSStatus                    status = noErr;
  5606.  
  5607.     // Recast DCL command.
  5608.     pDCLJump = (DCLJumpPtr) pDCLCommand;
  5609.  
  5610.     // Add a jump PCL.
  5611.     status = LynxFWIMPCLJump (pLynxPCLBuildState,
  5612.                               pDCLJump->pJumpDCLLabel,
  5613.                               (Ptr *) &(pDCLJump->compilerData));
  5614.  
  5615.     return (status);
  5616. }
  5617.  
  5618.  
  5619. ////////////////////////////////////////////////////////////////////////////////
  5620. //
  5621. // LynxFWIMAddLabelDCL
  5622. //
  5623. //   This proc adds a label DCL.
  5624. //zzz not optimal.
  5625. //
  5626.  
  5627. static OSStatus LynxFWIMAddLabelDCL(
  5628.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5629.     DCLCommandPtr                pDCLCommand)
  5630. {
  5631.     DCLLabelPtr                    pDCLLabel;
  5632.     OSStatus                    status = noErr;
  5633.  
  5634.     // Recast DCL command.
  5635.     pDCLLabel = (DCLLabelPtr) pDCLCommand;
  5636.  
  5637.     // Add a PCL label.
  5638.     status = LynxFWIMPCLLabel (pLynxPCLBuildState, pDCLLabel);
  5639.  
  5640.     // Resolve label.
  5641.     // This is complicated.  If there were no PCL for a label DCL, we would want
  5642.     // to resolve things that point to us (pDCLCommand) to point to the PCL for
  5643.     // the next "real" command (a transmit, or whatever).  But the next DCL has
  5644.     // not yet been compiled, (and it might be another label), so the PCL that we
  5645.     // would really like to point to doesn't exist yet.
  5646.     //
  5647.     // I think that what we do is have a dummy PCL that does correspond to this
  5648.     // label.  That PCL just does a NOP and falls through to the next PCL (which
  5649.     // doesn't exist yet).  That's what LynxFWIMPCLLabel created.  So we waste a
  5650.     // PCL and add a little latency to jumps, because once we jump to this label
  5651.     // we have to fall through at least one dummy PCL before we get any work done.
  5652.     //
  5653.     // A possible future optimization would be to pre-allocate the next non-label
  5654.     // PCL, so that we know where it is and we can jump to it, rather than making
  5655.     // a dummy PCL as the target.  That could be tricky because pre-allocation
  5656.     // could constrain us.
  5657.     //
  5658.     // A possible alternative optimization would be to take the finished PCL
  5659.     // program, and scan through it for jumps to NOPs, and bump them forward to
  5660.     // the next real command.  That could also be tricky if we try to make changes
  5661.     // to the program later, though.
  5662.     
  5663.     if (status == noErr)
  5664.         status = LynxFWIMResolveDCLLabel (pDCLLabel);
  5665.  
  5666.     return (status);
  5667. }
  5668.  
  5669.  
  5670. ////////////////////////////////////////////////////////////////////////////////
  5671. //
  5672. // LynxFWIMAddSetTagSyncBitsDCL
  5673. //
  5674. //   This proc adds a set tag and sync bits DCL.
  5675. //
  5676.  
  5677. static OSStatus LynxFWIMAddSetTagSyncBitsDCL(
  5678.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5679.     DCLCommandPtr                pDCLCommand)
  5680. {
  5681.     DCLSetTagSyncBitsPtr        pDCLSetTagSyncBits;
  5682.     LynxPCLPtr                    pPCL;
  5683.     UInt32                        currentBuffer;
  5684.     UInt32                        *pIsochPacketHeader;
  5685.     OSStatus                    status = noErr;
  5686.  
  5687.     // Recast DCL command.
  5688.     pDCLSetTagSyncBits = (DCLSetTagSyncBitsPtr) pDCLCommand;
  5689.  
  5690.     // Get current PCL.
  5691.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  5692.  
  5693.     // Make sure we have at least two commands left in PCL.
  5694.     if ((pLynxPCLBuildState->currentBuffer >= (pLynxPCLBuildState->lastBuffer - 3)) ||
  5695.         ((pLynxPCLBuildState->pclType != kLynxPCLAuxType) &&
  5696.          (pLynxPCLBuildState->pclType != kLynxPCLUnknownType)))
  5697.     {
  5698.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
  5699.         if (status == noErr)
  5700.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  5701.     }
  5702.     
  5703.     // Store location of PCL.
  5704.     if (status == noErr)
  5705.     {
  5706.         currentBuffer = pLynxPCLBuildState->currentBuffer;
  5707.         pDCLSetTagSyncBits->compilerData = (UInt32) &(pPCL->buffer[currentBuffer]);
  5708.     }
  5709.  
  5710.     // Get allocation for new isochronous packet header.
  5711.     if (status == noErr)
  5712.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, &pIsochPacketHeader);
  5713.  
  5714.     // Set up isochronous packet header.
  5715.     if (status == noErr)
  5716.     {
  5717.         *pIsochPacketHeader =
  5718.             (kFWTCodeIsochronousBlock << kFWIsochTCodePhase) |
  5719.             (pLynxPCLBuildState->isochChannelNum << kFWIsochChanNumPhase) |
  5720.             (pDCLSetTagSyncBits->tagBits << kFWIsochTagPhase) |
  5721.             (pDCLSetTagSyncBits->syncBits << kFWIsochSyPhase);
  5722.     }
  5723.  
  5724.     // Load temp with new header.
  5725.     // Phys addr of allocated word can be derived from PCL base addr
  5726.     if (status == noErr)
  5727.         status = LynxFWIMPCLLoadTemp (pLynxPCLBuildState,
  5728.                                       (Ptr) (pPCL->refCon + ((UInt32) pIsochPacketHeader - (UInt32) pPCL)));
  5729.  
  5730. #ifdef LynxVMDebug
  5731.         if (((Ptr) (pIsochPacketHeader)) !=
  5732.             ((Ptr) (pPCL->refCon + ((UInt32) pIsochPacketHeader - (UInt32) pPCL))))
  5733.         {
  5734.             sprintf (debugStr, "Isoch header PTR (B)  logical %08lx != physical %08lx",
  5735.                      (long) pIsochPacketHeader,
  5736.                      (long) (pPCL->refCon + ((UInt32) pIsochPacketHeader - (UInt32) pPCL)));
  5737.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  5738.         }
  5739. #endif
  5740.  
  5741.     // Store temp to engine data packet header (actually it's hidden in a PCL pool header).
  5742.     if (status == noErr)
  5743.     {
  5744.         pIsochPacketHeader =
  5745.             (pLynxPCLBuildState->pLynxDCLCompilerEngineData->isochPacketHeaderPhys);
  5746.         status = LynxFWIMPCLStoreTemp (pLynxPCLBuildState, (Ptr) pIsochPacketHeader);
  5747.     }
  5748.  
  5749.     return (status);
  5750. }
  5751.  
  5752.  
  5753. ////////////////////////////////////////////////////////////////////////////////
  5754. //
  5755. // LynxFWIMUpdateDCLListDCL
  5756. //
  5757. //   This proc adds a update DCL list DCL.
  5758. //
  5759.  
  5760. static OSStatus LynxFWIMUpdateDCLListDCL(
  5761.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5762.     DCLCommandPtr                pDCLCommand)
  5763. {
  5764.     OSStatus                    status = noErr;
  5765.     
  5766.     // Add an interrupt PCL.
  5767.     status = LynxFWIMPCLInterrupt (pLynxPCLBuildState,
  5768.                                    pDCLCommand,
  5769.                                    (Ptr *) &(pDCLCommand->compilerData));
  5770.     
  5771.     return (status);
  5772. }
  5773.  
  5774.  
  5775. ////////////////////////////////////////////////////////////////////////////////
  5776. //
  5777. // LynxFWIMTimeStampDCL
  5778. //
  5779. //   This proc adds a time stamp DCL.  This will build PCL commands to read the
  5780. // current cycle counter and write it into the PCL command.  The DCL compiler data
  5781. // will point to where the cycle timer is stored in the PCL command.
  5782. //
  5783.  
  5784. static OSStatus LynxFWIMTimeStampDCL(
  5785.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5786.     DCLCommandPtr                pDCLCommand)
  5787. {
  5788.     LynxFWIMDataPtr                pLynxFWIMData;
  5789.     LynxRegistersPtr            pLynxRegs;
  5790.     LynxPCLPtr                    pPCL,
  5791.                                 physPCL;
  5792.     UInt32                        *pPCLTimeStamp;
  5793.     OSStatus                    status = noErr;
  5794.     
  5795.     // Get current PCL.
  5796.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  5797.     
  5798.     // Get Lynx FWIM data and pointer to link registers.
  5799.     pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
  5800.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  5801.  
  5802.     // Make sure we have at least three commands left in PCL.
  5803.     if ((pLynxPCLBuildState->currentBuffer >= (pLynxPCLBuildState->lastBuffer - 4)) ||
  5804.         ((pLynxPCLBuildState->pclType != kLynxPCLAuxType) &&
  5805.          (pLynxPCLBuildState->pclType != kLynxPCLUnknownType)))
  5806.     {
  5807.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
  5808.         if (status == noErr)
  5809.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  5810.     }
  5811.     
  5812.     // Allocate word to store time stamp.
  5813.     if (status == noErr)
  5814.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, (UInt32 **) &pPCLTimeStamp);
  5815.  
  5816.     // Save time stamp pointer in compiler data.
  5817.     if (status == noErr)
  5818.         pDCLCommand->compilerData = (UInt32) pPCLTimeStamp;
  5819.  
  5820.     // Add PCL command to read cycle timer register.
  5821.     if (status == noErr)
  5822.     {
  5823.         status = LynxFWIMPCLLoadTemp
  5824.                     (pLynxPCLBuildState, (Ptr) &(pLynxRegs->cycleTimer));
  5825.     }
  5826.  
  5827.     // Add PCL command to write the cycle timer data into the PCL.
  5828.     if (status == noErr)
  5829.     {
  5830.         physPCL = (LynxPCLPtr) pPCL->refCon;  // Get physical address of PCL.
  5831.         status = LynxFWIMPCLStoreTemp
  5832.                     (pLynxPCLBuildState,
  5833.                      (Ptr) ((UInt32) physPCL + ((UInt32) pPCLTimeStamp - (UInt32) pPCL)));
  5834.     }
  5835.  
  5836.     return (status);
  5837. }
  5838.  
  5839.  
  5840. ////////////////////////////////////////////////////////////////////////////////
  5841. //
  5842. // LynxFWIMPCLStart
  5843. //
  5844. //   This proc creates a PCL build state record and a dummy PCL to start the
  5845. // chain.
  5846. //
  5847.  
  5848. static OSStatus    LynxFWIMPCLStart(
  5849.     LynxFWIMDataPtr                pLynxFWIMData,
  5850.     LynxPCLBuildStatePtr        *ppLynxPCLBuildState,
  5851.     LynxPCLPtr                    *ppPCL)
  5852. {
  5853.     LynxPCLBuildStatePtr        pLynxPCLBuildState;
  5854.     LynxPCLPtr                    pPCL;
  5855.     OSStatus                    status = noErr;
  5856.     
  5857.     // Allocate build state record.
  5858.     status = LynxFWIMAllocatePCLBuildState (pLynxFWIMData, &pLynxPCLBuildState);
  5859.     
  5860.     // Allocate start PCL.
  5861.     if (status == noErr)
  5862.         status = LynxFWIMAllocatePCL (pLynxPCLBuildState, &pPCL);
  5863.     
  5864.     // Create start PCL.
  5865.     if (status == noErr)
  5866.     {
  5867.         pPCL->buffer[0].control =
  5868.             EndianSwapImm32Bit ((kLynxDMA_NOP << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
  5869.     }
  5870.     
  5871.     // Fill in build state record.
  5872.     if (status == noErr)
  5873.     {
  5874.         pLynxPCLBuildState->pLynxFWIMData = pLynxFWIMData;
  5875.         pLynxPCLBuildState->pFirstPCL = pPCL;
  5876.         pLynxPCLBuildState->pCurrentPCL = pPCL;
  5877.         pLynxPCLBuildState->currentBuffer = 0;
  5878.         pLynxPCLBuildState->pclType = kLynxPCLStartType;
  5879.         pLynxPCLBuildState->refCon = 0;
  5880.         pLynxPCLBuildState->interrupt = false;
  5881.     }
  5882.     
  5883.     // Return results.
  5884.     if (status == noErr)
  5885.     {
  5886.         *ppLynxPCLBuildState = pLynxPCLBuildState;
  5887.         *ppPCL = pPCL;
  5888.     }
  5889.     else
  5890.     {
  5891.         *ppLynxPCLBuildState = nil;
  5892.         *ppPCL = nil;
  5893.     }
  5894.     
  5895.     return (status);
  5896. }
  5897.  
  5898.  
  5899. ////////////////////////////////////////////////////////////////////////////////
  5900. //
  5901. // LynxFWIMPCLAllocateWord
  5902. //
  5903. //   This proc allocates a word at the end of the current PCL.
  5904. //   The idea is to create a little storage space where we can keep data.
  5905. //   The space is at the end of the PCL so we don't try to execute it.
  5906. //   We might do a LOAD_TEMP from this location within the PCL (for example).
  5907. //
  5908.  
  5909. static OSStatus    LynxFWIMPCLAllocateWord(
  5910.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5911.     UInt32                        **ppWord)
  5912. {
  5913.     LynxPCLPtr                    pPCL;
  5914.     SInt32                        lastBuffer;
  5915.     UInt32                        bufferAllocationSize;
  5916.     UInt32                        *pWord;
  5917.     OSStatus                    status = noErr;
  5918.     
  5919.     // Get some data out of build state.
  5920.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  5921.     lastBuffer = pLynxPCLBuildState->lastBuffer;
  5922.     bufferAllocationSize = pLynxPCLBuildState->bufferAllocationSize;
  5923.     
  5924.     // Allocate word.  We may have to extend PCL.
  5925.     if ((lastBuffer >= 13) || (bufferAllocationSize >= 2))
  5926.     {
  5927.         lastBuffer--;
  5928.         bufferAllocationSize = 0;
  5929.     }
  5930.     if (lastBuffer < pLynxPCLBuildState->currentBuffer)
  5931.     {
  5932.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, pLynxPCLBuildState->pclType);
  5933.         if (status == noErr)
  5934.         {
  5935.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  5936.             lastBuffer = 12; //zzz should read back and reallocate if LynxFWIMPCLExtend can allocate a word.
  5937.             bufferAllocationSize = 0;
  5938.         }
  5939.     }
  5940.  
  5941.     if (status == noErr)
  5942.     {
  5943.         pWord = ((UInt32 *) (&(pPCL->buffer[lastBuffer].control))) +
  5944.                 (1 - bufferAllocationSize);
  5945.         bufferAllocationSize++;
  5946.     }
  5947.     
  5948.     // Update build state.
  5949.     if (status == noErr)
  5950.     {
  5951.         pLynxPCLBuildState->lastBuffer = lastBuffer;
  5952.         pLynxPCLBuildState->bufferAllocationSize = bufferAllocationSize;
  5953.     }
  5954.     
  5955.     // Return results.
  5956.     if (status == noErr)
  5957.         *ppWord = pWord;
  5958.     else
  5959.         *ppWord = nil;
  5960.     
  5961.     return (status);
  5962. }
  5963.  
  5964.  
  5965. ////////////////////////////////////////////////////////////////////////////////
  5966. //
  5967. // LynxFWIMPCLNew
  5968. //
  5969. //   This proc creates a new logical PCL.
  5970. //
  5971.  
  5972. static OSStatus    LynxFWIMPCLNew(
  5973.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  5974.     LynxPCLPtr                    *ppPCL,
  5975.     UInt32                        refCon)
  5976. {
  5977.     LynxFWIMDataPtr                pLynxFWIMData;
  5978.     LynxPCLPtr                    pPCL,
  5979.                                 pPrevPCL;
  5980.     OSStatus                    status = noErr;
  5981.     
  5982.     // Get data from build state.
  5983.     pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
  5984.     pPrevPCL = pLynxPCLBuildState->pCurrentPCL;
  5985.     
  5986.     // Allocate new PCL.
  5987.     status = LynxFWIMAllocatePCL (pLynxPCLBuildState, &pPCL);
  5988.     
  5989.     // Set up PCL.
  5990.     if (status == noErr)
  5991.     {
  5992.         pPCL->buffer[0].control =
  5993.             EndianSwapImm32Bit ((kLynxDMA_NOP << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
  5994.     }
  5995.     
  5996.     // Link previous PCL.
  5997.     if ((status == noErr) &&
  5998.         (((UInt32) pPrevPCL->nextPCL) == EndianSwapImm32Bit (kLynxCPLINVALID)))
  5999.     {
  6000.         // Elsewhere we check pPCL to see if it's kLynxCPLINVALID before we
  6001.         // dereference it.  But we just allocated pPCL so we know this one's safe.
  6002.         pPrevPCL->nextPCL = (UInt32 *) EndianSwap32Bit ((UInt32) pPCL->refCon);    // Phys addr
  6003.     }
  6004.  
  6005.     // Update build state.
  6006.     if (status == noErr)
  6007.     {
  6008.         pLynxPCLBuildState->pFirstPCL = pPCL;
  6009.         pLynxPCLBuildState->pCurrentPCL = pPCL;
  6010.         pLynxPCLBuildState->currentBuffer = 0;
  6011.         pLynxPCLBuildState->lastBuffer = 13;
  6012.         pLynxPCLBuildState->bufferAllocationSize = 0;
  6013.         pLynxPCLBuildState->pclType = kLynxPCLUnknownType;
  6014.         // We didn't put refCon in the PCL itself (that space is used for the physical
  6015.         // address), but maybe the copy in the BuildState will be used - so preserve it:
  6016.         pLynxPCLBuildState->refCon = refCon;
  6017.         pLynxPCLBuildState->interrupt = false;
  6018.     }
  6019.     
  6020.     // Return results.
  6021.     if (status == noErr)
  6022.         *ppPCL = pPCL;
  6023.     else
  6024.         *ppPCL = nil;
  6025.     
  6026.     return (status);
  6027. }
  6028.  
  6029.  
  6030. ////////////////////////////////////////////////////////////////////////////////
  6031. //
  6032. // LynxFWIMPCLNewIsochReceive
  6033. //
  6034. //   This proc creates a new logical isochronous receive PCL.
  6035. //zzz should we return PCL ptr?
  6036. //
  6037.  
  6038. static OSStatus    LynxFWIMPCLNewIsochReceive(
  6039.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6040.     LynxPCLPtr                    *ppPCL,
  6041.     UInt32                        refCon,
  6042.     UInt32                        speed)
  6043. {
  6044.     LynxPCLPtr                    pPCL;
  6045.     UInt32                        commandWord;
  6046.     OSStatus                    status = noErr;
  6047.     
  6048.     // Create a new PCL.
  6049.     status = LynxFWIMPCLNew (pLynxPCLBuildState, &pPCL, refCon);
  6050.     
  6051.     // Set pcl type and transfer command word.
  6052.     if (status == noErr)
  6053.     {
  6054.         // Build command word.
  6055.         commandWord = kLynxDMA_RCV << kLynxDMA_CMDPhase;
  6056.         
  6057.         pLynxPCLBuildState->pclType = kLynxPCLTransferType;
  6058.         pLynxPCLBuildState->commandWord = commandWord;
  6059.     }
  6060.     
  6061.     // Return results.
  6062.     if (status == noErr)
  6063.         *ppPCL = pPCL;
  6064.     else
  6065.         *ppPCL = nil;
  6066.     
  6067.     return (status);
  6068. }
  6069.  
  6070.  
  6071. ////////////////////////////////////////////////////////////////////////////////
  6072. //
  6073. // LynxFWIMPCLNewIsochTransmit
  6074. //
  6075. //   This proc creates a new logical isochronous transmit PCL.
  6076. //
  6077.  
  6078. static OSStatus    LynxFWIMPCLNewIsochTransmit(
  6079.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6080.     LynxPCLPtr                    *ppPCL,
  6081.     UInt32                        refCon,
  6082.     UInt32                        speed)
  6083. {
  6084.     LynxPCLPtr                    pPCL;
  6085.     UInt32                        commandWord;
  6086.     OSStatus                    status = noErr;
  6087.     
  6088.     // Create a new PCL.
  6089.     status = LynxFWIMPCLNew (pLynxPCLBuildState, &pPCL, refCon);
  6090.     
  6091.     // Set pcl type and transfer command word.
  6092.     if (status == noErr)
  6093.     {
  6094.         // Build command word.
  6095.         commandWord = kLynxDMA_XMT << kLynxDMA_CMDPhase;
  6096.         commandWord |= speed << kLynxDMA_xmit_spd_codePhase;
  6097.         commandWord |= kLynxDMA_Tramsmit_ISO;
  6098.         
  6099.         // Before sending, "wait" for Ready == 1 Condition.
  6100.         // We actually use this to stop the active sender, between packets.
  6101.         // We never actually wait and then resume.
  6102.         commandWord |= (kLynxDMAWaitReady1 << kLynxDMA_WAIT_SELPhase);
  6103.         
  6104.         pLynxPCLBuildState->pclType = kLynxPCLTransferType;
  6105.         pLynxPCLBuildState->commandWord = commandWord;
  6106.     }
  6107.     
  6108.     // Return results.
  6109.     if (status == noErr)
  6110.         *ppPCL = pPCL;
  6111.     else
  6112.         *ppPCL = nil;
  6113.     
  6114.     return (status);
  6115. }
  6116.  
  6117.  
  6118. ////////////////////////////////////////////////////////////////////////////////
  6119. //
  6120. // LynxFWIMPCLExtend
  6121. //
  6122. //   This proc extends a logical PCL with another physical one.
  6123. //zzz we should probably clear interrupts for previous PCL if interrupts are set
  6124. //
  6125.  
  6126. static OSStatus    LynxFWIMPCLExtend(
  6127.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6128.     UInt32                        pclType)
  6129. {
  6130.     LynxFWIMDataPtr                pLynxFWIMData;
  6131.     LynxPCLPtr                    pPCL,
  6132.                                 pPrevPCL;
  6133.     OSStatus                    status = noErr;
  6134.     
  6135.     // Get data from build state.
  6136.     pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
  6137.     pPrevPCL = pLynxPCLBuildState->pCurrentPCL;
  6138.     
  6139.     // Cannot extend transfer PCLs into another tranfer PCL.
  6140.     if ((pLynxPCLBuildState->pclType == kLynxPCLTransferType) &&
  6141.         (pclType == kLynxPCLTransferType))
  6142.     {
  6143.         status = -1;//zzz what should it really be?
  6144.     }
  6145.     
  6146.     // Allocate new PCL.
  6147.     if (status == noErr)
  6148.         status = LynxFWIMAllocatePCL (pLynxPCLBuildState, &pPCL);
  6149.     
  6150.     // Set up PCL.
  6151.     if (status == noErr)
  6152.     {
  6153.         pPCL->buffer[0].control =
  6154.             EndianSwapImm32Bit ((kLynxDMA_NOP << kLynxDMA_CMDPhase) | kLynxDMA_LAST_BUF);
  6155.     }
  6156.     
  6157.     // Link previous PCL.
  6158.     if ((status == noErr) &&
  6159.         (((UInt32) pPrevPCL->nextPCL) == EndianSwapImm32Bit (kLynxCPLINVALID)))
  6160.     {
  6161.         // No need to check for pPCL == kLynxCPLINVALID, because we just allocated it
  6162.         pPrevPCL->nextPCL = (UInt32 *) EndianSwap32Bit ((UInt32) pPCL->refCon);    // Phys addr
  6163.     }
  6164.  
  6165.     // Update build state.
  6166.     if (status == noErr)
  6167.     {
  6168.         pLynxPCLBuildState->pCurrentPCL = pPCL;
  6169.         pLynxPCLBuildState->currentBuffer = 0;
  6170.         pLynxPCLBuildState->lastBuffer = 13;
  6171.         pLynxPCLBuildState->bufferAllocationSize = 0;
  6172.         pLynxPCLBuildState->pclType = pclType;
  6173.     }
  6174.     
  6175.     return (status);
  6176. }
  6177.  
  6178.  
  6179. ////////////////////////////////////////////////////////////////////////////////
  6180. //
  6181. // LynxFWIMPCLLoadTemp
  6182. //
  6183. //   This proc adds a load to the temp register command to the PCL program.
  6184. //
  6185.  
  6186. static OSStatus    LynxFWIMPCLLoadTemp(
  6187.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6188.     Ptr                            pSource)
  6189. {
  6190.     OSStatus                    status = noErr;
  6191.     
  6192.     // pSource must by a physical address.
  6193.     // Whoever called us was reponsible for that
  6194.     
  6195.     status = LynxFWIMPCLAuxCommand
  6196.                 (pLynxPCLBuildState,
  6197.                  kLynxDMA_LOAD,
  6198.                  0,
  6199.                  (UInt32) pSource);
  6200.     
  6201.     return (status);
  6202. }
  6203.  
  6204.  
  6205. ////////////////////////////////////////////////////////////////////////////////
  6206. //
  6207. // LynxFWIMPCLStoreTemp
  6208. //
  6209. //   This proc adds a store from the temp register command to the PCL program.
  6210. //
  6211.  
  6212. static OSStatus    LynxFWIMPCLStoreTemp(
  6213.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6214.     Ptr                            pDest)
  6215. {
  6216.     OSStatus                    status = noErr;
  6217.     
  6218.     // pDest must by a physical address.
  6219.     // Whoever called us was reponsible for that
  6220.     
  6221.     status = LynxFWIMPCLAuxCommand
  6222.                 (pLynxPCLBuildState,
  6223.                  kLynxDMA_STORE_QUAD,
  6224.                  0,
  6225.                  (UInt32) pDest);
  6226.     
  6227.     return (status);
  6228. }
  6229.  
  6230.  
  6231. ////////////////////////////////////////////////////////////////////////////////
  6232. //
  6233. // LynxFWIMPCLStore0
  6234. //
  6235. //   This proc adds a store 0 command to the PCL program.
  6236. //
  6237.  
  6238. static OSStatus    LynxFWIMPCLStore0(
  6239.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6240.     Ptr                            pDest)
  6241. {
  6242.     OSStatus                    status = noErr;
  6243.     
  6244.     // pDest must by a physical address.
  6245.     // Whoever called us was reponsible for that
  6246.     
  6247.     status = LynxFWIMPCLAuxCommand
  6248.                 (pLynxPCLBuildState,
  6249.                  kLynxDMA_STORE0,
  6250.                  0,
  6251.                  (UInt32) pDest);
  6252.     
  6253.     return (status);
  6254. }
  6255.  
  6256.  
  6257. ////////////////////////////////////////////////////////////////////////////////
  6258. //
  6259. // LynxFWIMPCLStore1
  6260. //
  6261. //   This proc adds a store 1 command to the PCL program.
  6262. //
  6263.  
  6264. static OSStatus    LynxFWIMPCLStore1(
  6265.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6266.     Ptr                            pDest)
  6267. {
  6268.     OSStatus                    status = noErr;
  6269.     
  6270.     // pDest must by a physical address.
  6271.     // Whoever called us was reponsible for that
  6272.     
  6273.     status = LynxFWIMPCLAuxCommand
  6274.                 (pLynxPCLBuildState,
  6275.                  kLynxDMA_STORE1,
  6276.                  0,
  6277.                  (UInt32) pDest);
  6278.     
  6279.     return (status);
  6280. }
  6281.  
  6282.  
  6283. ////////////////////////////////////////////////////////////////////////////////
  6284. //
  6285. // LynxFWIMPCLCompareTemp16WithMask
  6286. //
  6287. //   This proc adds a 16 bit compare with mask command.
  6288. //
  6289.  
  6290. static OSStatus    LynxFWIMPCLCompareTemp16WithMask(
  6291.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6292.     UInt16                        compareValue,
  6293.     UInt16                        compareMask)
  6294. {
  6295.     OSStatus                    status = noErr;
  6296.     
  6297.     status = LynxFWIMPCLAuxCommand
  6298.                 (pLynxPCLBuildState,
  6299.                  kLynxDMA_COMPARE,
  6300.                  0,
  6301.                  (UInt32) ((compareMask << 16) | compareValue));
  6302.     
  6303.     return (status);
  6304. }
  6305.  
  6306.  
  6307. ////////////////////////////////////////////////////////////////////////////////
  6308. //
  6309. // LynxFWIMPCLBranchIfEqual
  6310. //
  6311. //   This proc adds a branch if equal command.
  6312. //
  6313.  
  6314. static OSStatus    LynxFWIMPCLBranchIfEqual(
  6315.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6316.     DCLLabelPtr                    pDCLLabel)
  6317. {
  6318.     LynxPCLPtr                    pCurrentPCL,
  6319.                                 pDCLLabelPCL;
  6320.     UInt32                        currentBuffer;
  6321.     UInt32                        branchTargetPhys;
  6322.     OSStatus                    status = noErr;
  6323.     
  6324.     // Check if label has been resolved.
  6325.     if ((pDCLLabelPCL = LynxFWIMGetDCLLabelPCLPtr (pDCLLabel)) != nil)
  6326.     {
  6327.         // The label has been resolved, so we can determine the actual
  6328.         // (physical) address of the PCL to jump to.  Put that in the
  6329.         // PCL we are writing, and we're all set.
  6330.         
  6331.         // pDCLLabelPCL can be kLynxCPLINVALID (0x00000001) if the branch
  6332.         // target is a phony DCL (ie stop on condition).  Don't lookup
  6333.         // a physical address for 1.
  6334.         // (Branching to kLynxCPLINVALID will cause the DMA to halt safely.)
  6335.         
  6336.         if (pDCLLabelPCL == (LynxPCLPtr) kLynxCPLINVALID)
  6337.             branchTargetPhys = kLynxCPLINVALID;
  6338.             else branchTargetPhys = pDCLLabelPCL->refCon;
  6339.             
  6340.         status = LynxFWIMPCLAuxCommand
  6341.                     (pLynxPCLBuildState,
  6342.                      kLynxDMA_BRANCH,
  6343.                      kLynxAuxConditionDMAReady1,
  6344.                      branchTargetPhys);
  6345.                      
  6346. #ifdef LynxVMDebug
  6347.         if (((Ptr) (pDCLLabelPCL)) !=
  6348.             ((Ptr) (branchTargetPhys)))
  6349.         {
  6350.             sprintf (debugStr, "BranchIfEqual target   logical %08lx != physical %08lx",
  6351.                      (long) pDCLLabelPCL,
  6352.                      (long) branchTargetPhys);
  6353.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  6354.         }
  6355. #endif
  6356.     }
  6357.     else
  6358.     {
  6359.         // The DCL we are jumping to has not yet been compiled into a PCL.
  6360.         // So make a note in the DCL's compilerData of the (logical) address
  6361.         // where the PCL branch target's (physical) address should go.
  6362.         // This will be updated with the target DCL gets compiled.  Note that
  6363.         // compilerData (in the targed DCL) may already contain a reference,
  6364.         // so copy that to our (yet unused) physical target, and replace it
  6365.         // with our own pointer.  This creates a list (of sorts) of references.
  6366.         
  6367.         status = LynxFWIMPCLAuxCommand
  6368.                     (pLynxPCLBuildState,
  6369.                      kLynxDMA_BRANCH,
  6370.                      kLynxAuxConditionDMAReady1,
  6371.                      (UInt32) pDCLLabel->compilerData);
  6372.  
  6373.         // Need to resolve label later.
  6374.         if (status == noErr)
  6375.         {
  6376.             pCurrentPCL = pLynxPCLBuildState->pCurrentPCL;
  6377.             currentBuffer = pLynxPCLBuildState->currentBuffer;
  6378.             
  6379.             // Stash in the target DCL the (logical) address where the
  6380.             // (physical) PCL target will need to go, once it is known.
  6381.             
  6382.             pDCLLabel->compilerData =
  6383.                 (UInt32) &(pCurrentPCL->buffer[currentBuffer - 1].address);
  6384.         }
  6385.     }
  6386.     
  6387.     return (status);
  6388. }
  6389.  
  6390.  
  6391. ////////////////////////////////////////////////////////////////////////////////
  6392. //
  6393. // LynxFWIMPCLJump
  6394. //
  6395. //   This proc sets the current PCL to jump to the given label.
  6396. //zzz we should probably start a new PCL so any subsequent DCLs are not run as
  6397. //zzz a part of the current PCL.
  6398. //
  6399.  
  6400. static OSStatus    LynxFWIMPCLJump(
  6401.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6402.     DCLLabelPtr                    pDCLLabel,
  6403.     Ptr                            *ppPCLCommand)
  6404. {
  6405.     LynxPCLPtr                    pCurrentPCL,
  6406.                                 pDCLLabelPCL;
  6407.     UInt32                        branchTargetPhys;
  6408.     OSStatus                    status = noErr;
  6409.     
  6410.     // Get current PCL.
  6411.     pCurrentPCL = pLynxPCLBuildState->pCurrentPCL;
  6412.     
  6413.     // Return PCL.
  6414.     if (ppPCLCommand != nil)
  6415.         *ppPCLCommand = (Ptr) pCurrentPCL;
  6416.     
  6417.     // Check if label has been resolved.
  6418.     if ((pDCLLabelPCL = LynxFWIMGetDCLLabelPCLPtr (pDCLLabel)) != nil)
  6419.     {
  6420.         // It would be legal to load ->nextPCL with kLynxCPLINVALID.
  6421.         // I don't think that ever happens, but do the right thing if so:
  6422.         
  6423.         if (pDCLLabelPCL == (LynxPCLPtr) kLynxCPLINVALID)
  6424.             branchTargetPhys = kLynxCPLINVALID;
  6425.             else branchTargetPhys = pDCLLabelPCL->refCon;
  6426.             
  6427.         pCurrentPCL->nextPCL =
  6428.             (UInt32 *) EndianSwap32Bit (branchTargetPhys);
  6429. #ifdef LynxVMDebug
  6430.         if (((Ptr) (pDCLLabelPCL)) !=
  6431.             ((Ptr) (branchTargetPhys)))
  6432.         {
  6433.             sprintf (debugStr, "Jump target   logical %08lx != physical %08lx",
  6434.                      (long) pDCLLabelPCL,
  6435.                      (long) branchTargetPhys);
  6436.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  6437.         }
  6438. #endif
  6439.     }
  6440.     else
  6441.     {
  6442.         // In case the DCL we're branching to already has one unresolved
  6443.         // reference, store that one in our branch field so we can put our
  6444.         // own address in the DCL.  See next comment.
  6445.         pCurrentPCL->nextPCL =
  6446.             (UInt32 *) EndianSwap32Bit ((UInt32) pDCLLabel->compilerData);
  6447.  
  6448.         // Need to resolve label later.
  6449.         // This is tricky.  Store the (logical) address of the (physical) jump
  6450.         // target address in compilerData.  Later, we'll update it.  Note that
  6451.         // if the spot to be updated contains another address (from previous
  6452.         // line) then we'll update that one too, and so on.
  6453.         pDCLLabel->compilerData = (UInt32) &(pCurrentPCL->nextPCL);
  6454.         
  6455.         // The resolution of all this is done by LynxFWIMResolveDCLLabel.
  6456.         // Labels are resolved as soon as they are added, but we might be
  6457.         // branching to a label that hasn't yet been added (it follows us).
  6458.     }
  6459.     
  6460.     return (status);
  6461. }
  6462.  
  6463.  
  6464. ////////////////////////////////////////////////////////////////////////////////
  6465. //
  6466. // LynxFWIMPCLInterrupt
  6467. //
  6468. //   This proc adds a command to issue an interrupt and add a link to the interrupt queue.
  6469. // This will create a PCL to store the current queue tail into the PCL.  This PCL
  6470. // will then set the queue tail to point into the PCL.
  6471. //
  6472. //   LOAD_TMP
  6473. //     interrupt_queue_tail
  6474. //
  6475. //   STORE_TMP
  6476. //     PCL_queue_link
  6477. //
  6478. //   LOAD_TMP
  6479. //     PCL_queue_link_logical_ptr
  6480. //
  6481. //   STORE_TMP
  6482. //     interrupt_queue_tail
  6483. //
  6484. // PCL_queue_link_logical_ptr: &PCL_queue_link
  6485. // {
  6486. // PCL_queue_link: quad storage
  6487. // DCL_logical_ptr: &DCL
  6488. // } LynxDCLProgramInterruptQueueElement;
  6489. //
  6490.  
  6491. static OSStatus    LynxFWIMPCLInterrupt(
  6492.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6493.     DCLCommandPtr                pDCLCommand,
  6494.     Ptr                            *ppPCLCommand)
  6495. {
  6496.     LynxFWIMDataPtr                pLynxFWIMData,
  6497.                                 physLynxFWIMData;
  6498.     LynxPCLPtr                    pPCL,
  6499.                                 physPCL;
  6500.     DCLCommandPtr                *ppDCLCommand;
  6501.     LynxDCLProgramInterruptQueueElementPtr
  6502.                                 *ppDCLInterruptLink,
  6503.                                 *ppDCLInterrupt;
  6504.     UInt32                        pclChannelNum;
  6505.     UInt32                        currentBuffer;
  6506.     UInt32                        bufferNum;
  6507.     OSStatus                    status = noErr;
  6508.  
  6509.     // Set interrupt flag in build state.
  6510.     pLynxPCLBuildState->interrupt = true;
  6511.     
  6512.     // Get current PCL.
  6513.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  6514.     
  6515.     // Make sure we have at least six commands left in PCL.
  6516.     if ((pLynxPCLBuildState->currentBuffer >= (pLynxPCLBuildState->lastBuffer - 7)) ||
  6517.         ((pLynxPCLBuildState->pclType != kLynxPCLAuxType) &&
  6518.          (pLynxPCLBuildState->pclType != kLynxPCLUnknownType)))
  6519.     {
  6520.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
  6521.         if (status == noErr)
  6522.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  6523.     }
  6524.     
  6525.     // Set interrupt bit in preceeding commands.
  6526.     //zzz should only have to do it for first command.
  6527.     if (status == noErr)
  6528.     {
  6529.         currentBuffer = pLynxPCLBuildState->currentBuffer;
  6530.         for (bufferNum = 0; bufferNum < currentBuffer; bufferNum++)
  6531.             pPCL->buffer[bufferNum].control |= EndianSwapImm32Bit (kLynxDMA_INT);
  6532.     }
  6533.  
  6534.     // Return pointer to command.
  6535.     if ((status == noErr) && (ppPCLCommand != nil))
  6536.         *ppPCLCommand = (Ptr) &(pPCL->buffer[currentBuffer]);
  6537.  
  6538.     // Get Lynx FWIM data.
  6539.     pLynxFWIMData = pLynxPCLBuildState->pLynxFWIMData;
  6540.     physLynxFWIMData = (LynxFWIMDataPtr) pLynxFWIMData->fwimDataPhys;
  6541.  
  6542.     // Get physical address of current PCL.
  6543.     physPCL = (LynxPCLPtr) pPCL->refCon;
  6544.     
  6545.     // Allocate a word (DCL_logical_ptr) to hold logical pointer to the DCL.
  6546.     if (status == noErr)
  6547.     {
  6548.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, (UInt32 **) &ppDCLCommand);
  6549.         if (status == noErr)
  6550.             *ppDCLCommand = pDCLCommand;
  6551.     }
  6552.  
  6553.     // Allocate a word (PCL_queue_link) to save interrupt queue link.
  6554.     if (status == noErr)
  6555.     {
  6556.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState,
  6557.                                           (UInt32 **) &ppDCLInterruptLink);
  6558.     }
  6559.  
  6560.     // Allocate a word (PCL_queue_link_logical_ptr) to hold logical pointer to
  6561.     // PCL's LynxDCLProgramInterruptQueueElement.
  6562.     if (status == noErr)
  6563.     {
  6564.         status = LynxFWIMPCLAllocateWord (pLynxPCLBuildState, (UInt32 **) &ppDCLInterrupt);
  6565.         if (status == noErr)
  6566.             *ppDCLInterrupt = (LynxDCLProgramInterruptQueueElementPtr) ppDCLInterruptLink;
  6567.     }
  6568.  
  6569.     // Load the interrupt queue tail.
  6570.     //   LOAD_TMP
  6571.     //     interrupt_queue_tail
  6572.     if (status == noErr)
  6573.     {
  6574.         pclChannelNum = pLynxPCLBuildState->pclChannelNum;
  6575.         status = LynxFWIMPCLLoadTemp
  6576.                     (pLynxPCLBuildState,
  6577.                      (Ptr) &(physLynxFWIMData->pDCLInterruptTail[pclChannelNum]));
  6578.     }
  6579.  
  6580.     // Store the interrupt queue tail into interrupt queue element link.
  6581.     //   STORE_TMP
  6582.     //     PCL_queue_link
  6583.     if (status == noErr)
  6584.     {
  6585.         status =
  6586.             LynxFWIMPCLStoreTemp
  6587.                 (pLynxPCLBuildState,
  6588.                  (Ptr) ((UInt32) physPCL + ((UInt32) ppDCLInterruptLink - (UInt32) pPCL)));
  6589.     }
  6590.  
  6591.     // Load pointer to our interrupt queue element.
  6592.     //   LOAD_TMP
  6593.     //     PCL_queue_link_logical_ptr
  6594.     if (status == noErr)
  6595.     {
  6596.         status =
  6597.             LynxFWIMPCLLoadTemp
  6598.                 (pLynxPCLBuildState,
  6599.                  (Ptr) ((UInt32) physPCL + ((UInt32) ppDCLInterrupt - (UInt32) pPCL)));
  6600.     }
  6601.  
  6602.     // Store pointer to our interrupt queue element into interrupt queue tail.
  6603.     if (status == noErr)
  6604.     {
  6605.         status = LynxFWIMPCLStoreTemp 
  6606.                     (pLynxPCLBuildState,
  6607.                      (Ptr) &(physLynxFWIMData->pDCLInterruptTail[pclChannelNum]));
  6608.     }
  6609.  
  6610.     return (status);
  6611. }
  6612.  
  6613.  
  6614. ////////////////////////////////////////////////////////////////////////////////
  6615. //
  6616. // LynxFWIMPCLAuxCommand
  6617. //
  6618. //   This proc adds the given auxiliary command to the PCL program.
  6619. // Branching is dependent upon the way currentBuffer is set.
  6620. //zzz need to special case if prior PCL was async send
  6621. //
  6622. // In many cases, auxParam is a physical address.  Whoever calls us
  6623. // must have worked it out in advance.
  6624. //
  6625.  
  6626. static OSStatus    LynxFWIMPCLAuxCommand(
  6627.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6628.     UInt32                        auxCommand,
  6629.     UInt32                        waitBranchCondition,
  6630.     UInt32                        auxParam)
  6631. {
  6632.     LynxPCLPtr                    pPCL;
  6633.     UInt32                        pclType;
  6634.     UInt32                        currentBuffer;
  6635.     UInt32                        commandWord;
  6636.     OSStatus                    status = noErr;
  6637.     
  6638.     // Get data from build state.
  6639.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  6640.     pclType = pLynxPCLBuildState->pclType;
  6641.     currentBuffer = pLynxPCLBuildState->currentBuffer;
  6642.     
  6643.     // Check if we need to extend PCL.
  6644.     if (((pclType != kLynxPCLAuxType) &&
  6645.          (pclType != kLynxPCLUnknownType)) ||
  6646.         (currentBuffer == pLynxPCLBuildState->lastBuffer))
  6647.     {
  6648.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLAuxType);
  6649.         if (status == noErr)
  6650.         {
  6651.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  6652.             pclType = kLynxPCLAuxType;
  6653.             currentBuffer = 0;
  6654.         }
  6655.     }
  6656.     
  6657.     // Set PCL type to kLynxPCLAuxType if it's unknown.
  6658.     if ((status == noErr) && (pclType == kLynxPCLUnknownType))
  6659.         pLynxPCLBuildState->pclType = kLynxPCLAuxType;
  6660.     
  6661.     // If we're not on the first command, clear last command last buf bit.
  6662.     if ((status == noErr) && (currentBuffer > 0))
  6663.         pPCL->buffer[currentBuffer - 1].control &= EndianSwapImm32Bit (~kLynxDMA_LAST_BUF);
  6664.  
  6665.     // Add command.
  6666.     if (status == noErr)
  6667.     {
  6668.         // Build command word.
  6669.         commandWord = auxCommand << kLynxDMA_CMDPhase;
  6670.         commandWord |= waitBranchCondition << kLynxDMA_BRANCH_SELPhase;
  6671.         commandWord |= kLynxDMA_LAST_BUF;
  6672.         if (pLynxPCLBuildState->interrupt)
  6673.             commandWord |= kLynxDMA_INT;
  6674.         
  6675.         // Add it.
  6676.         pPCL->buffer[currentBuffer].control = EndianSwap32Bit (commandWord);
  6677.         // See above - sometimes this is a physical address
  6678.         pPCL->buffer[currentBuffer].address = (UInt32 *) EndianSwap32Bit (auxParam);
  6679.         pLynxPCLBuildState->currentBuffer++;
  6680.     }
  6681.     
  6682.     return (status);
  6683. }
  6684.  
  6685.  
  6686. ////////////////////////////////////////////////////////////////////////////////
  6687. //
  6688. // LynxFWIMPCLAddTransferBuffer
  6689. //
  6690. //   This proc adds the given transfer buffer to the PCL program.  It will
  6691. // return a pointer to the PCL command if ppPCLCommand is non-nil.
  6692. // Branching is dependent upon the way currentBuffer is set.
  6693. //zzz need to special case if prior PCL was async send
  6694. //
  6695.  
  6696. static OSStatus    LynxFWIMPCLAddTransferBuffer(
  6697.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6698.     Ptr                            buffer,
  6699.     UInt32                        bufferSize,
  6700.     Ptr                            *ppPCLCommand,
  6701.     UInt32                        bufferAddrType)
  6702. {
  6703.     LynxPCLPtr                    pPCL;
  6704.     UInt32                        pclType;
  6705.     UInt32                        currentBuffer;
  6706.     UInt32                        commandWord;
  6707.     PhysicalAddress                physAddrs[4];        // enough for 800 mbits
  6708.     UInt32                        pageCount, pageSize, firstPageSize;
  6709.     OSStatus                    status = noErr;
  6710.     
  6711.     // Get data from build state.
  6712.     pPCL = pLynxPCLBuildState->pCurrentPCL;
  6713.     pclType = pLynxPCLBuildState->pclType;
  6714.     currentBuffer = pLynxPCLBuildState->currentBuffer;
  6715.  
  6716.     // Check if we're at the end of the PCL.
  6717.     // Can't transfer accross multiple PCLs.
  6718.     // For now, assume we'll need at most two slots for page crossing.
  6719.     // That handles packets up to 4097 bytes.
  6720.     // At 200 mbits, max isoch packet is 2500.
  6721.     // A 400 mbit channel > 80% reservation can break us.
  6722.     
  6723.     if ((pclType == kLynxPCLTransferType) &&
  6724.         (currentBuffer + 1 >= pLynxPCLBuildState->lastBuffer))
  6725.     {
  6726.         status = -1;//zzz what should it really be?
  6727.         FWDebugStr ((ConstStr255Param) "\pLynxFWIMPCLAddTransferBuffer - failed due to full PCL");
  6728.     }
  6729.     
  6730.     // Check if we need to extend PCL.
  6731.     if ((status == noErr) &&
  6732.         (pclType != kLynxPCLTransferType) &&
  6733.         (pclType != kLynxPCLUnknownType))
  6734.     {
  6735.         status = LynxFWIMPCLExtend (pLynxPCLBuildState, kLynxPCLTransferType);
  6736.         if (status == noErr)
  6737.         {
  6738.             pPCL = pLynxPCLBuildState->pCurrentPCL;
  6739.             currentBuffer = 0;
  6740.         }
  6741.     }
  6742.     
  6743.     // Set PCL type to kLynxPCLTransferType if it's unknown.
  6744.     if ((status == noErr) && (pclType == kLynxPCLUnknownType))
  6745.         pLynxPCLBuildState->pclType = kLynxPCLTransferType;
  6746.     
  6747.     // If we're not on the first command, clear last command last buf bit.
  6748.     // Also clear the wait condition on the current command, if transmit.
  6749.     if ((status == noErr) && (currentBuffer > 0))
  6750.     {
  6751.         pPCL->buffer[currentBuffer - 1].control &= EndianSwapImm32Bit (~kLynxDMA_LAST_BUF);
  6752.         
  6753.         // Seems like there ought to be a better way to do this.
  6754.         // Note, duplicated below in page-crossing case
  6755.         if (((pLynxPCLBuildState->commandWord & kLynxDMA_CMD) >> kLynxDMA_CMDPhase) == kLynxDMA_XMT)
  6756.             pLynxPCLBuildState->commandWord &= ~kLynxDMA_WAIT_SEL;
  6757.     }
  6758.     
  6759.     // When VM is turned on, we may have to translate the provided buffer into a physical
  6760.     // address.  If the buffer straddles a page boundary, we may need two (or more)
  6761.     // buffers (>2 buffers only possible at 400 megabits or above).  We built a lookup
  6762.     // table of logical/physical buffers before we started compling, so we use a lookup
  6763.     // function now.  Also note that there can be more than one DCL in this PCL.  For
  6764.     // example, a PacketStart DCL followed by a Packet DCL (for isoch transmit) must be
  6765.     // merged into a single PCL (Lynx allows only one PCL per packet)
  6766.     
  6767.     // Finally, keep in mind that the buffers may be updated later, and the number of
  6768.     // page boundary crossings may change.  But, the upper bound is low - no more than
  6769.     // two crossings at 400 mbits.  However, if the user assembles a transmit packet
  6770.     // out of many small buffers, we don't want to waste slots in the PCL.  Also some
  6771.     // PCL slots may be used up by AUX commands and inline data.
  6772.     
  6773.     // Some buffers are already physical (they point to Lynx registers, PCLs, or other
  6774.     // data we already prepared as physical).
  6775.     
  6776.     // Add command.
  6777.     if (status == noErr)
  6778.     {
  6779.         // Add it.
  6780.         if (bufferAddrType == kLynxPhysicalBuffer)
  6781.         {
  6782.             // If it's a physical buffer, it doesn't matter if we cross page boundaries.
  6783.             // We can do it all with a single transfer command.  (Physical buffers are
  6784.             // usually only 2 (maybe 4) bytes, last I checked.)
  6785.             
  6786.             // Build command word.
  6787.             commandWord = pLynxPCLBuildState->commandWord;
  6788.             commandWord |= bufferSize << kLynxDMA_TransferCountPhase;
  6789.             commandWord |= kLynxDMA_LAST_BUF;
  6790.             pPCL->buffer[currentBuffer].control = EndianSwap32Bit (commandWord);
  6791.             pPCL->buffer[currentBuffer].address = (UInt32 *) EndianSwap32Bit ((UInt32) buffer);
  6792.  
  6793.             pLynxPCLBuildState->currentBuffer++;
  6794.         }
  6795.         else        // logical buffer
  6796.         {
  6797.             pageCount = LynxFWIMDataMapToPhysical (pLynxPCLBuildState->pLynxDCLCompilerEngineData,
  6798.                                                    buffer, bufferSize, physAddrs);
  6799. #ifdef LynxVMDebug
  6800.             if (((Ptr) (buffer)) !=
  6801.                 ((Ptr) (physAddrs[0])))
  6802.             {
  6803.                 sprintf (debugStr, "Payload lookup   logical %08lx != physical %08lx",
  6804.                          (long) buffer,
  6805.                          (long) physAddrs[0]);
  6806.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  6807.             }
  6808. #endif
  6809.             if (pageCount > 2)
  6810.                 FWDebugStr ((ConstStr255Param) "\pOops, too many pages for DMA (?!)");
  6811.  
  6812.             // Should cache this or make lookup figure it all out for us
  6813.             pageSize = GetLogicalPageSize ();
  6814.             
  6815.             // Make this all work regardless of page size and speed.  Who knows what might change.
  6816.             if (pageCount == 1)
  6817.                 firstPageSize = bufferSize;
  6818.             else
  6819.                 firstPageSize = pageSize - ((UInt32) buffer & (pageSize - 1));
  6820.             
  6821.             // Build command word.
  6822.             commandWord = pLynxPCLBuildState->commandWord;
  6823.             commandWord |= firstPageSize << kLynxDMA_TransferCountPhase;
  6824.             if (pageCount == 1) commandWord |= kLynxDMA_LAST_BUF;
  6825.             pPCL->buffer[currentBuffer].control = EndianSwap32Bit (commandWord);
  6826.             pPCL->buffer[currentBuffer].address = (UInt32 *) EndianSwap32Bit ((UInt32) physAddrs[0]);
  6827.  
  6828.             // We are now mid-packet.  Clear wait from here to end of packet.
  6829.             // (duplicated above)
  6830.             if (((pLynxPCLBuildState->commandWord & kLynxDMA_CMD) >> kLynxDMA_CMDPhase) == kLynxDMA_XMT)
  6831.                 pLynxPCLBuildState->commandWord &= ~kLynxDMA_WAIT_SEL;
  6832.  
  6833.             if (pageCount > 1)        // assume it's 2
  6834.             {
  6835.                 // Build command word.
  6836.                 commandWord = pLynxPCLBuildState->commandWord;
  6837.                 commandWord |= (bufferSize - firstPageSize) << kLynxDMA_TransferCountPhase;
  6838.                 commandWord |= kLynxDMA_LAST_BUF;
  6839.                 pPCL->buffer[currentBuffer + 1].control = EndianSwap32Bit (commandWord);
  6840.                 pPCL->buffer[currentBuffer + 1].address = (UInt32 *) EndianSwap32Bit ((UInt32) physAddrs[1]);
  6841.             }
  6842.             
  6843.             pLynxPCLBuildState->currentBuffer += pageCount;
  6844.         }
  6845.         
  6846.         // Return pointer to command.
  6847.         if (ppPCLCommand != nil)
  6848.             *ppPCLCommand = (Ptr) &(pPCL->buffer[currentBuffer]);
  6849.  
  6850.     }
  6851.     
  6852.     return (status);
  6853. }
  6854.  
  6855.  
  6856. ////////////////////////////////////////////////////////////////////////////////
  6857. //
  6858. // LynxFWIMResolveDCLLabel
  6859. //
  6860. //   This proc resolves the given DCL label.
  6861. //
  6862.  
  6863. static OSStatus    LynxFWIMResolveDCLLabel(
  6864.     DCLLabelPtr                    pDCLLabel)
  6865. {
  6866.     DCLCommandPtr                pDCLCommand;
  6867.     LynxPCLPtr                    pPCL,
  6868.                                 *pLabelDependency,
  6869.                                 *pNextLabelDependency;
  6870.     UInt32                        branchTargetPhys;
  6871.     OSStatus                    status = noErr;
  6872.     
  6873.     // The label pDCLLabel has just been added to the PCL program.  It may already
  6874.     // be the branch target of one or more existing PCLs.  If so, they have stashed
  6875.     // a pointer to where they hold their branch target in pDCLLabel->compilerData.
  6876.     // Furthermore, if what is pointed to is not nil, it is another pointer to an
  6877.     // unresolved label, etc.  So we follow that chain, filling in our real PCL
  6878.     // address.  Note that we will need to fill in the physical address, since now
  6879.     // is the final stage in assigning jump addresses.
  6880.     
  6881.     // Resolve all of the dependencies.
  6882.     if (pDCLLabel->compilerData != nil)
  6883.     {
  6884.         // Get PCL for this label.
  6885.         // PCL will be the PCL for the next non label DCL.
  6886.         //zzz what if label DCL is last in list???
  6887.         pDCLCommand = pDCLLabel->pNextDCLCommand;
  6888.         while ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLLabelOp)
  6889.             pDCLCommand = pDCLCommand->pNextDCLCommand;
  6890.         pPCL = LynxFWIMGetPCLFromDCL (pDCLCommand);
  6891.         
  6892.         // Resolve label to this PCL.
  6893.         if (pPCL != nil)
  6894.         {
  6895.             pLabelDependency = (LynxPCLPtr *) pDCLLabel->compilerData;
  6896.             while (pLabelDependency != nil)
  6897.             {
  6898.                 // Sometimes we branch to kLynxCPLINVALID in order to stop the DMA.
  6899.                 // I'm not sure if that can happen here, but just in case, check
  6900.                 // pPCL for kLynxCPLINVALID before dereferencing it.
  6901.                 
  6902.                 if (pPCL == (LynxPCLPtr) kLynxCPLINVALID)
  6903.                     branchTargetPhys = kLynxCPLINVALID;
  6904.                     else branchTargetPhys = pPCL->refCon;
  6905.                     
  6906.                 pNextLabelDependency = (LynxPCLPtr *) *pLabelDependency;
  6907.                 *pLabelDependency = (LynxPCLPtr) EndianSwap32Bit (branchTargetPhys);
  6908.                 pLabelDependency = pNextLabelDependency;
  6909. #ifdef LynxVMDebug
  6910.                 if (((Ptr) (pPCL)) !=
  6911.                     ((Ptr) (branchTargetPhys)))
  6912.                 {
  6913.                     sprintf (debugStr, "Resolved target   logical %08lx != physical %08lx",
  6914.                              (long) pPCL,
  6915.                              (long) branchTargetPhys);
  6916.                     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  6917.                 }
  6918. #endif
  6919.             }
  6920.         }
  6921.         pDCLLabel->compilerData = nil;
  6922.     }
  6923.     
  6924.     return (status);
  6925. }
  6926.  
  6927.  
  6928. ////////////////////////////////////////////////////////////////////////////////
  6929. //
  6930. // LynxFWIMGetDCLLabelPCLPtr
  6931. //
  6932. //   This proc returns a pointer to the PCL corresponding to the given label
  6933. // if the given label is resolved.  A return value of nil means the label has
  6934. // not been resolved.
  6935. //
  6936.  
  6937. static LynxPCLPtr    LynxFWIMGetDCLLabelPCLPtr(
  6938.     DCLLabelPtr                    pDCLLabel)
  6939. {
  6940.     DCLCommandPtr                pDCLCommand;
  6941.     LynxPCLPtr                    pDCLLabelPCL;
  6942.  
  6943.     // Search for next command that is not another label.
  6944.     pDCLCommand = pDCLLabel->pNextDCLCommand;
  6945.     while (pDCLCommand != nil)
  6946.     {
  6947.         if ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLLabelOp)
  6948.             pDCLCommand = pDCLCommand->pNextDCLCommand;
  6949.         else
  6950.             break;
  6951.     }
  6952.  
  6953.     // Return results.
  6954.     if (pDCLCommand != nil)
  6955.         pDCLLabelPCL = LynxFWIMGetPCLFromDCL (pDCLCommand);
  6956.     else
  6957.         pDCLLabelPCL = (LynxPCLPtr) kLynxCPLINVALID;
  6958.  
  6959.     return (pDCLLabelPCL);
  6960. }
  6961.  
  6962.  
  6963. ////////////////////////////////////////////////////////////////////////////////
  6964. //
  6965. // LynxFWIMPCLLabel
  6966. //
  6967. //   This proc adds a DCL label to the PCL program.
  6968. //
  6969.  
  6970. static OSStatus    LynxFWIMPCLLabel(
  6971.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  6972.     DCLLabelPtr                    pDCLLabel)
  6973. {
  6974.     DCLCommandPtr                pDCLCommand;
  6975.     LynxPCLPtr                    pPCL;
  6976.     OSStatus                    status = noErr;
  6977.  
  6978.     // We don't need to do anything if this label already has a PCL associated
  6979.     // with it.
  6980.     if (LynxFWIMGetDCLLabelPCLPtr (pDCLLabel) == nil)
  6981.     {
  6982.         // Start new PCL.
  6983.         status = LynxFWIMPCLNew (pLynxPCLBuildState, &pPCL, (UInt32) pDCLLabel);
  6984.  
  6985.         // Set next non label DCL's compiler data to the new PCL.
  6986.         // When the next non label DCL is compiled, its compiler data will be updated
  6987.         // to point to the PCL command within the PCL created above.
  6988.         //zzz what if label is last in program?
  6989.         if (status == noErr)
  6990.         {
  6991.             pDCLCommand = pDCLLabel->pNextDCLCommand;
  6992.             while ((pDCLCommand->opcode & ~kFWDCLOpFlagMask) == kDCLLabelOp)
  6993.                 pDCLCommand = pDCLCommand->pNextDCLCommand;
  6994.             pDCLCommand->compilerData = (UInt32) pPCL;
  6995.         }
  6996.     }
  6997.  
  6998.     return (status);
  6999. }
  7000.  
  7001.  
  7002. ////////////////////////////////////////////////////////////////////////////////
  7003. //
  7004. // LynxFWIMGetPCLFromDCL
  7005. //
  7006. //   This proc returns a pointer to the start of the PCL corresponding to the
  7007. // given DCL.  Label DCLs do not have corresponding PCLs.
  7008. //zzz well, label DCLs do, so maybe we should integrate LynxFWIMGetDCLLabelPCLPtr
  7009. //zzz with this routine
  7010. //
  7011.  
  7012. static LynxPCLPtr    LynxFWIMGetPCLFromDCL(
  7013.     DCLCommandPtr                pDCLCommand)
  7014. {
  7015.     LynxPCLPtr                    pPCL;
  7016.     
  7017.     // Base of PCL is the compiler data masked with kPCLAlignmentMask.
  7018.     pPCL = (LynxPCLPtr) (pDCLCommand->compilerData & kPCLAlignmentMask);
  7019.     
  7020.     // I have a lingering suspicion that I might have done something wrong
  7021.     // here that can (rarely) cause a physical PCL pointer to get dereferenced.
  7022.     // But I only saw it happen once and I wasn't really paying attention,
  7023.     // so maybe it was just a fluke.
  7024.     
  7025.     return (pPCL);
  7026. }
  7027.  
  7028.  
  7029. ////////////////////////////////////////////////////////////////////////////////
  7030. //
  7031. // LynxFWIMDCLCompilerNotification
  7032. //
  7033. //   This proc handles update notifications for the DCL to PCL compiler.
  7034. //
  7035.  
  7036. static OSStatus        LynxFWIMDCLCompilerNotification(
  7037.     DCLProgramID                dclProgramID,
  7038.     UInt32                        notificationType,
  7039.     DCLCommandPtr                *dclCommandList,
  7040.     UInt32                        numDCLCommands)
  7041. {
  7042.     OSStatus                    status = noErr;
  7043.  
  7044.     switch (notificationType)
  7045.     {
  7046.         case kFWDCLUpdateNotification :
  7047.             status = LynxFWIMDCLCompilerUpdateNotification (dclProgramID,
  7048.                                                             dclCommandList,
  7049.                                                             numDCLCommands);
  7050.             break;
  7051.  
  7052.         case kFWDCLModifyNotification :
  7053.             status = LynxFWIMDCLCompilerModifyNotification (dclProgramID,
  7054.                                                             dclCommandList,
  7055.                                                             numDCLCommands);
  7056.             break;
  7057.  
  7058.         default :
  7059.             status = paramErr;
  7060.             break;
  7061.     }
  7062.  
  7063.     return (status);
  7064. }
  7065.  
  7066.  
  7067. ////////////////////////////////////////////////////////////////////////////////
  7068. //
  7069. // LynxFWIMDCLCompilerUpdateNotification
  7070. //
  7071. //   This proc handles update notifications for the DCL to PCL compiler.  This will
  7072. // do any neccessary CheckPointIOs and update any DCL status fields.
  7073. //zzz do the right stuff in here
  7074. //
  7075.  
  7076. static OSStatus        LynxFWIMDCLCompilerUpdateNotification(
  7077.     DCLProgramID                dclProgramID,
  7078.     DCLCommandPtr                *dclCommandList,
  7079.     UInt32                        numDCLCommands)
  7080. {
  7081.     DCLCommandPtr                pDCLCommand;
  7082.     UInt32                        dclCommandNum;
  7083.     OSStatus                    status = noErr;
  7084.  
  7085.     for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
  7086.     {
  7087.         pDCLCommand = dclCommandList[dclCommandNum];
  7088.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  7089.         {
  7090.             case kDCLTimeStampOp :
  7091.                 LynxFWIMUpdateDCLTimeStamp (pDCLCommand);
  7092.                 break;
  7093.  
  7094.             default :
  7095.                 break;
  7096.         }
  7097.     }
  7098.  
  7099.     return (status);
  7100. }
  7101.  
  7102.  
  7103. ////////////////////////////////////////////////////////////////////////////////
  7104. //
  7105. // LynxFWIMUpdateDCLTimeStamp
  7106. //
  7107. //   This proc updates a DCL time stamp.  It reads the time stamp out of a PCL
  7108. // and writes it into the timeStamp field of the DCL.
  7109. //
  7110.  
  7111. static OSStatus        LynxFWIMUpdateDCLTimeStamp(
  7112.     DCLCommandPtr                pDCLCommand)
  7113. {
  7114.     DCLTimeStampPtr                pDCLTimeStamp;
  7115.     UInt32                        *pTimeStamp;
  7116.     OSStatus                    status = noErr;
  7117.  
  7118.     // Recast DCL command.
  7119.     pDCLTimeStamp = (DCLTimeStampPtr) pDCLCommand;
  7120.  
  7121.     // Copy time stamp from PCL.
  7122.     // Add one cycle since we're running ahead.
  7123.     //zzz have to be able to compute run ahead.  It can vary depending upon packet size.
  7124.     pTimeStamp = (UInt32 *) pDCLTimeStamp->compilerData;
  7125.     pDCLTimeStamp->timeStamp = EndianSwap32Bit (*pTimeStamp) + (1 << 12);
  7126.  
  7127.     return (status);
  7128. }
  7129.  
  7130.  
  7131. ////////////////////////////////////////////////////////////////////////////////
  7132. //
  7133. // LynxFWIMDCLCompilerModifyNotification
  7134. //
  7135. //   This proc handles modification notifications for the DCL to PCL compiler.
  7136. //zzz break this routine up
  7137. //
  7138.  
  7139. static OSStatus        LynxFWIMDCLCompilerModifyNotification(
  7140.     DCLProgramID                dclProgramID,
  7141.     DCLCommandPtr                *dclCommandList,
  7142.     UInt32                        numDCLCommands)
  7143. {
  7144.     DCLCommandPtr                pDCLCommand;
  7145.     DCLJumpPtr                    pDCLJump;
  7146.     DCLLabelPtr                    pDCLLabel;
  7147.     LynxPCLPtr                    pJumpPCL,
  7148.                                 pLabelPCL;
  7149.  
  7150.     DCLTransferPacketPtr        pDCLTransferPacket;
  7151.     LynxPCLPtr                    pTransferPacketPCL;
  7152.     UInt32                        pclControl;
  7153.     UInt32                        dclCommandNum;
  7154.     UInt32                        branchTargetPhys;
  7155.  
  7156.     OSStatus                    status = noErr;
  7157.  
  7158.     for (dclCommandNum = 0; dclCommandNum < numDCLCommands; dclCommandNum++)
  7159.     {
  7160.         // Get DCL command to update.
  7161.         pDCLCommand = *dclCommandList++;
  7162.  
  7163.         // Update command.
  7164.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  7165.         {
  7166.             case kDCLJumpOp :
  7167.  
  7168.                 // Recast.
  7169.                 pDCLJump = (DCLJumpPtr) pDCLCommand;
  7170.  
  7171.                 // Get label we're jumping to.
  7172.                 pDCLLabel = pDCLJump->pJumpDCLLabel;
  7173.  
  7174.                 // Get PCLs for jump and label DCLs.
  7175.                 pJumpPCL = LynxFWIMGetPCLFromDCL ((DCLCommandPtr) pDCLJump);
  7176.                 pLabelPCL = LynxFWIMGetDCLLabelPCLPtr (pDCLLabel);
  7177.  
  7178.                 if (pLabelPCL == (LynxPCLPtr) kLynxCPLINVALID)
  7179.                     branchTargetPhys = kLynxCPLINVALID;
  7180.                 else
  7181.                     branchTargetPhys = pLabelPCL->refCon;
  7182.                     
  7183.                 // Update jump PCL.
  7184.                 pJumpPCL->nextPCL = (UInt32 *) EndianSwap32Bit ((UInt32) branchTargetPhys);
  7185.  
  7186. #ifdef LynxVMDebug
  7187.                 if (((Ptr) (pLabelPCL)) !=
  7188.                     ((Ptr) (branchTargetPhys)))
  7189.                 {
  7190.                     sprintf (debugStr, "Updated jump   logical %08lx != physical %08lx",
  7191.                              (long) pLabelPCL,
  7192.                              (long) branchTargetPhys);
  7193.                     FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  7194.                 }
  7195. #endif
  7196.                 break;
  7197.  
  7198.             case kDCLSendPacketWithHeaderStartOp :
  7199.                 //zzz support other transfer packet commands.
  7200.  
  7201.                 FWDebugStr ((ConstStr255Param) "/pOops, tried to update buffer, don't know how!");
  7202.  
  7203. // What would we do?
  7204. // We can't do what's done below - that fills in new PCL buffer addresses.  They aren't yet known.
  7205. // What we want is a PrepareMemoryForIO that covers all buffers in the new scheme.  I notice that
  7206. // we don't actually modify the base DCLs - I think we will have to do that.  So make one pass to
  7207. // modify the base DCLs.  Then call the general-purpose memory preparation routine, and let it
  7208. // create an all-new ioPrep (keep the old one).  Once that's done, we can re-scan the list of
  7209. // changes and make updates knowing the new physical addresses.  Finally, once the updates are
  7210. // all in place, it's impossible for any stale DMA to take place, so we can CheckpointIO on
  7211. // the old ioPrep struct and free its resources.  [Technically we should wait one packet to make
  7212. // sure that whatever Lynx's current DMA engine is doing is up to date.  Probably a good-enough
  7213. // way to do this is to postpone the CheckpointIO until before the NEXT round of updates, though
  7214. // that is somewhat wasteful if it ties down old buffers that aren't in use anymore...]
  7215. //
  7216. // We should find a safe way to make multiple updates to a PCL.  The user is in trouble anyway
  7217. // if we're changing a PCL while it runs, because they'll get the wrong data, but we want to
  7218. // make sure we don't send an illegally large packet (bad for 1394 bus) or overflow our receiver
  7219. // (could be bad for Lynx).  Perhaps we should copy command[0], set it to NOP+last, update the
  7220. // others, then update command[0].  That's safe unless we are inside the PCL but past command[0].
  7221. // After we set command[0] to NOP, we can check the DMA current cmd and make sure it is elsewhere.
  7222. //
  7223. // I don't suppose the user is required to use jump-updates to deactivate part of the program
  7224. // before updating that part?  That would be 100% safe if we know the jump-update worked on time.
  7225. //
  7226. // For safety we should probably pre-allocate a physAddr table and a rangeTable for two ioPrep
  7227. // structs, then we don't have to do any allocs here.  (though PrepareMemForIO might anyway).
  7228. // We know that the total number of buffers can't change, so rangeTable is OK.  When we prepare
  7229. // the physAddr table we should work out both the true size and the worst-case size.  Use the
  7230. // worst-case for alloc, use the true for PrepareMemoryForIO
  7231.  
  7232.                 // Recast.
  7233.                 pDCLTransferPacket = (DCLTransferPacketPtr) pDCLCommand;
  7234.  
  7235.                 // Get PCL.
  7236.                 pTransferPacketPCL =
  7237.                     LynxFWIMGetPCLFromDCL ((DCLCommandPtr) pDCLTransferPacket);
  7238.  
  7239.                 // Update buffer size of transfer PCL.
  7240.                 pclControl = EndianSwap32Bit (pTransferPacketPCL->buffer[0].control);
  7241.                 pclControl = (pclControl & ~kLynxDMA_TransferCount) |
  7242.                              ((pDCLTransferPacket->size) << kLynxDMA_TransferCountPhase);
  7243.                 pTransferPacketPCL->buffer[0].control = EndianSwap32Bit (pclControl);
  7244.  
  7245.                 // Update buffer address of transfer PCL.
  7246.                 // WARNING WARNING this won't work with VM on - this is a logical address
  7247.                 pTransferPacketPCL->buffer[0].address =
  7248.                     (UInt32 *) EndianSwap32Bit ((UInt32) pDCLTransferPacket->buffer);
  7249.  
  7250.                 break;
  7251.  
  7252.             default :
  7253.  
  7254.                 break;
  7255.         }
  7256.     }
  7257.  
  7258.     return (status);
  7259. }
  7260.  
  7261.  
  7262. ////////////////////////////////////////////////////////////////////////////////
  7263. //
  7264. // LynxFWIMAllocatePCLBuildState
  7265. //
  7266. //   This proc allocates a PCL build state record.
  7267. //zzz we really don't need this.  should be allocated by other methods (stack?)
  7268. //
  7269.  
  7270. static OSStatus    LynxFWIMAllocatePCLBuildState(
  7271.     LynxFWIMDataPtr                pLynxFWIMData,
  7272.     LynxPCLBuildStatePtr        *ppLynxPCLBuildState)
  7273. {
  7274.     LynxPCLBuildStatePtr        pLynxPCLBuildState;
  7275.     OSStatus                    status = noErr;
  7276.     
  7277.     // Allocate memory for record.
  7278.     pLynxPCLBuildState =
  7279.         (LynxPCLBuildStatePtr) PoolAllocateResident (sizeof (LynxPCLBuildState), true);
  7280.     if (pLynxPCLBuildState == nil)
  7281.         status = memFullErr;
  7282.  
  7283.     // Return results.
  7284.     if (status == noErr)
  7285.         *ppLynxPCLBuildState = pLynxPCLBuildState;
  7286.     else
  7287.         *ppLynxPCLBuildState = nil;
  7288.  
  7289.     return (status);
  7290. }
  7291.  
  7292.  
  7293. ////////////////////////////////////////////////////////////////////////////////
  7294. //
  7295. // LynxFWIMAllocatePCL
  7296. //
  7297. //   This proc allocates a PCL.
  7298. //
  7299.  
  7300. static OSStatus    LynxFWIMAllocatePCL(
  7301.     LynxPCLBuildStatePtr        pLynxPCLBuildState,
  7302.     LynxPCLPtr                    *ppPCL)
  7303. {
  7304.     LynxPCLPoolDataPtr            pLynxPCLPoolData;
  7305.     LynxPCLPtr                    pPCL,
  7306.                                 pclPool;
  7307.     UInt32                        pclPoolPhys;
  7308.     UInt32                        nextFreePCL;
  7309.     IOPreparationTable            *ioPrep;
  7310.     UInt32                        pageSize, allocSize;
  7311.     Ptr                            p;
  7312.     OSStatus                    status = noErr;
  7313.     
  7314.     // Get PCL pool data record.
  7315.     pLynxPCLPoolData = pLynxPCLBuildState->pLynxPCLPoolDataList;
  7316.     
  7317.     // Get PCL pool and next free PCL index.
  7318.     if (pLynxPCLPoolData != nil)
  7319.     {
  7320.         pclPool = pLynxPCLPoolData->alignedPCLPoolBase;
  7321.         pclPoolPhys = pLynxPCLPoolData->alignedPCLPoolBasePhys;
  7322.         nextFreePCL = pLynxPCLPoolData->nextFreePCL;
  7323.     }
  7324.     else
  7325.     {
  7326.         pclPool = nil;
  7327.     }
  7328.     
  7329.     // Allocate new pool if current pool is exhausted.
  7330.     // This pool needs to be aligned to the PCL size for the PCL compilation logic
  7331.     // to work properly.  Pool size can exceed one phys page as long as we have an
  7332.     // allocator which gives us contiguous pages.
  7333.     
  7334.     if ((pclPool == nil) || (nextFreePCL >= kPCLPoolSize))
  7335.     {
  7336.         pageSize = GetLogicalPageSize ();
  7337.         allocSize = sizeof (LynxPCLPoolData) + sizeof (LynxPCL);
  7338.         
  7339.         // Not knowing if MemAllocPhysCont returns page-aligned data, we need to
  7340.         // add one page to align and one more to flush out the end of the struct.
  7341.         // (Could be done more tightly.)
  7342.         
  7343.         allocSize = (allocSize / pageSize) + 3;        // sloppy
  7344.         
  7345.         p = MemAllocatePhysicallyContiguous (allocSize * pageSize, true);
  7346.         if (p != nil)
  7347.         {
  7348.             // Page align
  7349.             pLynxPCLPoolData = (LynxPCLPoolDataPtr)
  7350.                 (((UInt32) p + (pageSize - 1)) & ~(pageSize - 1));
  7351.             
  7352.             // Store original
  7353.             pLynxPCLPoolData->poolAllocatedAddress = (LogicalAddress) p;
  7354.             
  7355.             ioPrep = &pLynxPCLPoolData->ioPrep;
  7356.             
  7357.             // Prepare for IO and get physical address
  7358.             ioPrep->options = kIOLogicalRanges | kIOIsInput | kIOIsOutput;
  7359.             ioPrep->addressSpace = kCurrentAddressSpaceID;            // default
  7360.             ioPrep->granularity = 0;                                // do it all now
  7361.             ioPrep->firstPrepared = 0;
  7362.             ioPrep->mappingEntryCount = allocSize - 1;                // # of pages we will use
  7363.             ioPrep->logicalMapping = 0;
  7364.             ioPrep->physicalMapping = pLynxPCLPoolData->physAddrs;    // return list of phys addrs
  7365.             ioPrep->rangeInfo.range.base = (void *) pLynxPCLPoolData;
  7366.             ioPrep->rangeInfo.range.length = (allocSize - 1) * pageSize;
  7367.             
  7368.             // The CheckpointIO is in LynxFWIMDeallocatePCLPools
  7369.             status = PrepareMemoryForIO (ioPrep);
  7370.             if (status != noErr)
  7371.             {
  7372.                 sprintf (debugStr, "PCL Pool PrepMemIO status %ld    logical %08lx physical %08lx len %lx",
  7373.                          (long) status,
  7374.                          (long) ioPrep->rangeInfo.range.base,
  7375.                          (long) pLynxPCLPoolData->physAddrs[0],
  7376.                          (long) ioPrep->rangeInfo.range.length);
  7377.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  7378.             }
  7379.  
  7380.             pLynxPCLPoolData->pNextLynxPCLPoolData =
  7381.                 pLynxPCLBuildState->pLynxPCLPoolDataList;
  7382.             pLynxPCLBuildState->pLynxPCLPoolDataList = pLynxPCLPoolData;
  7383.             // Never use pclPoolDummy.  (This is the only place)  It does not index
  7384.             // the true aligned PCLs.  Use alignedPCLPoolBase as an array instead.
  7385.             pLynxPCLPoolData->alignedPCLPoolBase = (LynxPCLPtr)
  7386.                 (((UInt32) &(pLynxPCLPoolData->pclPoolDummy[1])) & kPCLAlignmentMask);
  7387.  
  7388.             pLynxPCLPoolData->alignedPCLPoolBasePhys =
  7389.                 (UInt32) pLynxPCLPoolData->physAddrs[0] +
  7390.                 ((UInt32) pLynxPCLPoolData->alignedPCLPoolBase - (UInt32) pLynxPCLPoolData);
  7391.             
  7392.             // In the first allocated pool, we keep space for the isoch packet
  7393.             // header (for transmit).  Work out its location and store it away.
  7394.             // Note we only really need to do this the first time.  Note also
  7395.             // that whoever is going to use this better make a copy before the
  7396.             // second time we come here.
  7397.             
  7398.             pLynxPCLPoolData->isochPacketHeaderPhys = (PhysicalAddress)
  7399.                 ((UInt32) pLynxPCLPoolData->physAddrs[0] +
  7400.                  ((UInt32) &(pLynxPCLPoolData->isochPacketHeader) - (UInt32) pLynxPCLPoolData));
  7401.                         
  7402. #ifdef LynxVMDebug
  7403.             if (((Ptr) (&(pLynxPCLPoolData->isochPacketHeader))) !=
  7404.                 ((Ptr) (pLynxPCLPoolData->isochPacketHeaderPhys)))
  7405.             {
  7406.                 sprintf (debugStr, "Isoch header store  logical %08lx != physical %08lx",
  7407.                          (long) (&(pLynxPCLPoolData->isochPacketHeader)),
  7408.                          (long) pLynxPCLPoolData->isochPacketHeaderPhys);
  7409.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  7410.             }
  7411. #endif
  7412.             nextFreePCL = 0;
  7413.             pclPool = pLynxPCLPoolData->alignedPCLPoolBase;
  7414.             pclPoolPhys = pLynxPCLPoolData->alignedPCLPoolBasePhys;
  7415.         }
  7416.         else
  7417.         {
  7418.             status = memFullErr;
  7419.         }
  7420.     }
  7421.     
  7422.     // Allocate PCL from pool.
  7423.     if (status == noErr)
  7424.     {
  7425.         pPCL = &(pclPool[nextFreePCL++]);
  7426.         pPCL->refCon = pclPoolPhys + (((UInt32) pPCL) - ((UInt32) pclPool));
  7427.         pLynxPCLPoolData->nextFreePCL = nextFreePCL;
  7428. #ifdef LynxVMDebug
  7429.         if (((Ptr) (pPCL)) != ((Ptr) (pPCL->refCon)))
  7430.         {
  7431.             sprintf (debugStr, "PCL alloc logical %08lx != physical %08lx",
  7432.                      (long) pPCL,
  7433.                      (long) pPCL->refCon);
  7434.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  7435.         }
  7436. #endif
  7437.     }
  7438.  
  7439.     // Initialize the PCL.
  7440.     if (status == noErr)
  7441.     {
  7442.         pPCL->nextPCL = (UInt32 *) EndianSwap32Bit (kLynxCPLINVALID);
  7443.         pPCL->nextPCLAlt = (UInt32 *) EndianSwapImm32Bit (kLynxCPLINVALID);
  7444.         pPCL->status = EndianSwapImm32Bit (0);
  7445.         pPCL->remaining = EndianSwapImm32Bit (0);
  7446.         pPCL->nextAddress = (UInt32 *) EndianSwapImm32Bit (0);
  7447.     }
  7448.  
  7449.     // Return results.
  7450.     if (status == noErr)
  7451.         *ppPCL = pPCL;
  7452.     else
  7453.         *ppPCL = nil;
  7454.  
  7455.     return (status);
  7456. }
  7457.  
  7458.  
  7459. ////////////////////////////////////////////////////////////////////////////////
  7460. //
  7461. // LynxFWIMDeallocatePCLPools
  7462. //
  7463. //   This proc deallocates the given list of PCL pools.
  7464. //
  7465.  
  7466. static void LynxFWIMDeallocatePCLPools(
  7467.     LynxPCLPoolDataPtr            pLynxPCLPoolDataList)
  7468. {
  7469.     LynxPCLPoolDataPtr            pLynxPCLPoolData,
  7470.                                 pNextLynxPCLPoolData;
  7471.     OSStatus                    status = noErr;
  7472.  
  7473.     // Deallocate each pool in list.
  7474.     pLynxPCLPoolData = pLynxPCLPoolDataList;
  7475.     while (pLynxPCLPoolData != nil)
  7476.     {
  7477.         pNextLynxPCLPoolData = pLynxPCLPoolData->pNextLynxPCLPoolData;
  7478.         status = CheckpointIO (pLynxPCLPoolData->ioPrep.preparationID, kNilOptions);
  7479.         if (status != noErr)
  7480.         {
  7481.             sprintf (debugStr, "PCL Pool CheckpointIO status %ld    ID was %08lx",
  7482.                      (long) status,
  7483.                      (long) pNextLynxPCLPoolData->ioPrep.preparationID);
  7484.             FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  7485.         }
  7486.         if (MemDeallocatePhysicallyContiguous (pLynxPCLPoolData->poolAllocatedAddress) != noErr)
  7487.             FWDebugStr ((ConstStr255Param) "\p Dealloc error!!");
  7488.         pLynxPCLPoolData = pNextLynxPCLPoolData;
  7489.     }
  7490. }
  7491.  
  7492.  
  7493. ////////////////////////////////////////////////////////////////////////////////
  7494. //
  7495. // LynxFWIMRunDCLProgram
  7496. //
  7497. //   This proc uses the given packet to run through the DCL program.
  7498. //   This is obsolete, but shows how one could manually process DCLs.
  7499. //
  7500.  
  7501. static void    LynxFWIMRunDCLProgram(
  7502.     LynxIsochPortDataPtr        pLynxIsochPortData,
  7503.     Ptr                            packetBuffer,
  7504.     UInt32                        packetSize,
  7505.     DCLCommandPtr                *ppDCLCommand)
  7506. {
  7507.     DCLCommandPtr                pDCLCommand;
  7508.     DCLCallProcPtr                pDCLCallProc;
  7509.     DCLJumpPtr                    pDCLJump;
  7510.     UInt32                        packetSizeLeft;
  7511.     Boolean                        waitForPacket;
  7512.  
  7513.     // Process packet data.
  7514.     pDCLCommand = *ppDCLCommand;
  7515.     packetSizeLeft = packetSize;
  7516.     waitForPacket = false;
  7517.     while ((pDCLCommand != nil) && (!waitForPacket))
  7518.     {
  7519.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  7520.         {
  7521.             case kDCLReceivePacketStartOp :
  7522.                 if (packetSize > 0)
  7523.                 {
  7524.                     LynxFWIMDCLReceivePacketStart
  7525.                         (&packetBuffer, &packetSize, &pDCLCommand, &waitForPacket);
  7526.                 }
  7527.                 else
  7528.                 {
  7529.                     waitForPacket = true;
  7530.                 }
  7531.                 break;
  7532.  
  7533.             case kDCLReceiveBufferOp :
  7534.                 packetBuffer += sizeof (UInt32); // Skip header//zzz not quite right.
  7535.                 LynxFWIMDCLReceiveBuffer
  7536.                     (&packetBuffer, &packetSize, &pDCLCommand, &waitForPacket);
  7537.                 break;
  7538.                 
  7539.             case kDCLCallProcOp :
  7540.                 pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
  7541.                 FWCallDCLCallProc (pLynxIsochPortData->dclProgramID, pDCLCallProc);
  7542.                 pDCLCommand = pDCLCommand->pNextDCLCommand;
  7543.                 break;
  7544.                 
  7545.             case kDCLJumpOp :
  7546.                 pDCLJump = (DCLJumpPtr) pDCLCommand;
  7547.                 pDCLCommand = (DCLCommandPtr) pDCLJump->pJumpDCLLabel;
  7548.                 break;
  7549.  
  7550.             default :
  7551.                 pDCLCommand = pDCLCommand->pNextDCLCommand;
  7552.                 break;
  7553.         }
  7554.     }
  7555.     
  7556.     // Update current DCL command.
  7557.     *ppDCLCommand = pDCLCommand;
  7558. }
  7559.  
  7560.  
  7561. ////////////////////////////////////////////////////////////////////////////////
  7562. //
  7563. // LynxFWIMDCLReceivePacketStart
  7564. //
  7565. //   This proc processes a DCL receive packet command.
  7566. //   This is obsolete, but shows how one could manually process DCLs.
  7567. //
  7568.  
  7569. static void    LynxFWIMDCLReceivePacketStart(
  7570.     Ptr                            *pPacketBuffer,
  7571.     UInt32                        *pPacketSize,
  7572.     DCLCommandPtr                *ppDCLCommand,
  7573.     Boolean                        *pWaitForPacket)
  7574. {
  7575.     DCLTransferPacketPtr        pDCLTransferPacket;
  7576.     UInt32                        packetSize;
  7577.     UInt32                        dclPacketSize;
  7578.     UInt32                        transferSize;
  7579.  
  7580.     // Recast DCL command.
  7581.     pDCLTransferPacket = (DCLTransferPacketPtr) *ppDCLCommand;
  7582.     
  7583.     // Compute transfer size.
  7584.     dclPacketSize = pDCLTransferPacket->size;
  7585.     packetSize = *pPacketSize + sizeof (UInt32);//zzz include header
  7586.     if (dclPacketSize > packetSize)
  7587.         transferSize = packetSize;
  7588.     else
  7589.         transferSize = dclPacketSize;
  7590.  
  7591.     // Transfer the packet data.
  7592.     if (transferSize > 0)
  7593.         BlockCopy (*pPacketBuffer, pDCLTransferPacket->buffer, transferSize);
  7594.     
  7595.     // We're done with DCL and packet.
  7596.     *ppDCLCommand = pDCLTransferPacket->pNextDCLCommand;
  7597.     *pPacketSize = 0;
  7598.     *pWaitForPacket = false;
  7599. }
  7600.  
  7601.  
  7602. ////////////////////////////////////////////////////////////////////////////////
  7603. //
  7604. // LynxFWIMDCLReceiveBuffer
  7605. //
  7606. //   This proc processes a DCL receive buffer command.
  7607. //   This is obsolete, but shows how one could manually process DCLs.
  7608. //
  7609.  
  7610. static void    LynxFWIMDCLReceiveBuffer(
  7611.     Ptr                            *pPacketBuffer,
  7612.     UInt32                        *pPacketSize,
  7613.     DCLCommandPtr                *ppDCLCommand,
  7614.     Boolean                        *pWaitForPacket)
  7615. {
  7616.     DCLTransferBufferPtr        pDCLTransferBuffer;
  7617.     UInt32                        bufferSizeLeft;
  7618.     UInt32                        packetSize;
  7619.     UInt32                        transferSize;
  7620.  
  7621.     // Recast DCL command.
  7622.     pDCLTransferBuffer = (DCLTransferBufferPtr) *ppDCLCommand;
  7623.     
  7624.     // Compute transfer size.
  7625.     bufferSizeLeft = pDCLTransferBuffer->size - pDCLTransferBuffer->bufferOffset;
  7626.     packetSize = *pPacketSize;
  7627.     if (bufferSizeLeft > packetSize)
  7628.         transferSize = packetSize;
  7629.     else
  7630.         transferSize = bufferSizeLeft;
  7631.  
  7632.     // Transfer the packet data.
  7633.     if (transferSize > 0)
  7634.     {
  7635.         BlockCopy (*pPacketBuffer,
  7636.                    pDCLTransferBuffer->buffer + pDCLTransferBuffer->bufferOffset,
  7637.                    transferSize);
  7638.         
  7639.         *pPacketBuffer += transferSize;
  7640.         *pPacketSize -= transferSize;
  7641.         pDCLTransferBuffer->bufferOffset += transferSize;
  7642.     }
  7643.     
  7644.     // Check if we're done with this DCL or need another packet.
  7645.     if (pDCLTransferBuffer->bufferOffset == pDCLTransferBuffer->size)
  7646.     {
  7647.         *ppDCLCommand = pDCLTransferBuffer->pNextDCLCommand;
  7648.         *pWaitForPacket = false;
  7649.     }
  7650.     else
  7651.     {
  7652.         *pWaitForPacket = true;
  7653.     }
  7654. }
  7655.  
  7656.  
  7657. ////////////////////////////////////////////////////////////////////////////////
  7658. //
  7659. // LynxFWIMAllocateIsochPort
  7660. //
  7661. //   This routine will allocate an isochronous channel.
  7662. //zzz must make sure that port is not already in use.
  7663. //zzz should do more error checking.
  7664. //zzz we may need to keep a list of isoch port data records.
  7665. //
  7666.  
  7667. static OSStatus LynxFWIMAllocateIsochPort(
  7668.     FWIMAllocateIsochPortParamsPtr
  7669.                                 pFWIMAllocateIsochPortParams,
  7670.     UInt32                        *pCommandAcceptance)
  7671. {
  7672.     FWIMCommandParamsPtr        pFWIMCommandParams;
  7673.     LynxFWIMDataPtr                pLynxFWIMData;
  7674.     LynxIsochPortDataPtr        pLynxIsochPortData = nil;
  7675.     LynxRegistersPtr            pLynxRegs;
  7676.     UInt32                        dmaChannelNum;
  7677.     UInt32                        isochChannelNum;
  7678.     Boolean                        talking;
  7679.     OSStatus                    status = noErr;
  7680.  
  7681. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMAllocateIsochPort");
  7682.  
  7683.     // Get our internal data.
  7684.     pFWIMCommandParams = &(pFWIMAllocateIsochPortParams->fwimCommandParams);
  7685.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  7686.  
  7687.     // Set pending command.
  7688.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMAllocateIsochPortParams;
  7689.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  7690.  
  7691.     // Get base address of Lynx registers.
  7692.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  7693.     
  7694.     // Are we talking?
  7695.     talking = pFWIMAllocateIsochPortParams->talking;
  7696.  
  7697.     // Get dma channel number.
  7698.     if (talking)
  7699.         dmaChannelNum = kIsochTransmitDMA;
  7700.     else
  7701.         dmaChannelNum = kIsochReceiveDMA;
  7702.  
  7703.     // Create an isoch port data record.
  7704.     pLynxIsochPortData =
  7705.         (LynxIsochPortDataPtr) PoolAllocateResident (sizeof (LynxIsochPortData), true);
  7706.     if (pLynxIsochPortData != nil)
  7707.     {
  7708.         pLynxFWIMData->lynxIsochPortDataList[dmaChannelNum] = pLynxIsochPortData;
  7709.         pLynxIsochPortData->originalDCLProgramID =
  7710.             pFWIMAllocateIsochPortParams->dclProgramID;
  7711.         pLynxIsochPortData->translatedDCLProgramID = kInvalidDCLProgramID;
  7712.         pLynxIsochPortData->channelNum = pFWIMAllocateIsochPortParams->channelNum;
  7713.         pLynxIsochPortData->speed = pFWIMAllocateIsochPortParams->speed;
  7714.         pLynxIsochPortData->talking = talking;
  7715.     }
  7716.     else
  7717.     {
  7718.         status = memFullErr;
  7719.     }
  7720.     
  7721.     // Compile a PCL program from DCL program.
  7722.     if (status == noErr)
  7723.     {
  7724.         // Check if DCL program must be translated.
  7725.         if (LynxFWIMIsCompilableDCLProgram (pLynxIsochPortData->originalDCLProgramID))
  7726.         {
  7727.             pLynxIsochPortData->dclProgramID = pLynxIsochPortData->originalDCLProgramID;
  7728.         }
  7729.         else
  7730.         {
  7731.             //zzz need to be able to deallocate this.
  7732.             status = FWTranslateDCLProgram (pLynxIsochPortData->originalDCLProgramID,
  7733.                                             &(pLynxIsochPortData->translatedDCLProgramID));
  7734.             if (status == noErr)
  7735.             {
  7736.                 pLynxIsochPortData->dclProgramID =
  7737.                     pLynxIsochPortData->translatedDCLProgramID;
  7738.             }
  7739.         }
  7740.         
  7741.         // Compile the DCL program.
  7742.         if (status == noErr)
  7743.         {
  7744.             status = LynxFWIMCompileDCLProgram
  7745.                         (pLynxFWIMData,
  7746.                          pLynxIsochPortData->dclProgramID,
  7747.                          dmaChannelNum,
  7748.                          pLynxIsochPortData->channelNum,
  7749.                          pLynxIsochPortData->speed);
  7750.         }
  7751.  
  7752.         // Set start, stop, and release procedures for DCL program.
  7753.         if (status == noErr)
  7754.         {
  7755.             if (talking)
  7756.             {
  7757.                 FWSetDCLProgramStartProc (pLynxIsochPortData->dclProgramID,
  7758.                                           LynxFWIMStartTalkingDCLProgram);
  7759.                 FWSetDCLProgramStopProc (pLynxIsochPortData->dclProgramID,
  7760.                                          LynxFWIMStopTalkingDCLProgram);
  7761.                 FWSetDCLProgramReleaseProc (pLynxIsochPortData->dclProgramID,
  7762.                                             LynxFWIMReleaseDCLProgram);
  7763.             }
  7764.             else
  7765.             {
  7766.                 FWSetDCLProgramStartProc (pLynxIsochPortData->dclProgramID,
  7767.                                           LynxFWIMStartListeningDCLProgram);
  7768.                 FWSetDCLProgramStopProc (pLynxIsochPortData->dclProgramID,
  7769.                                          LynxFWIMStopListeningDCLProgram);
  7770.                 FWSetDCLProgramReleaseProc (pLynxIsochPortData->dclProgramID,
  7771.                                             LynxFWIMReleaseDCLProgram);
  7772.             }
  7773.         }
  7774.     }
  7775.  
  7776.     // Set up appropriate DMA channel.
  7777.     if (status == noErr)
  7778.     {
  7779.         // Quiet the DMA channel.
  7780.         pLynxRegs->dmaChannel[dmaChannelNum].control = EndianSwapImm32Bit (0);
  7781.         SynchronizeIO ();
  7782.  
  7783.         // Switch to isochronous transmit mode if we're talking.
  7784.         if (talking)
  7785.         {
  7786.             pLynxFWIMData->isochTransmitMode = true;
  7787.             LynxFWIMSetupFIFOs (pLynxFWIMData);
  7788.         }
  7789.  
  7790.         // Set up comparators to receive on this port's channel.
  7791.         if (!talking)
  7792.         {
  7793.             isochChannelNum = pLynxIsochPortData->channelNum;
  7794.             pLynxRegs->dmaComparator[dmaChannelNum].value0 =
  7795.                 EndianSwapImm32Bit (isochChannelNum << kLynxCMP0_FIELD2_MASKPhase);
  7796.             pLynxRegs->dmaComparator[dmaChannelNum].mask0 =
  7797.                 EndianSwapImm32Bit ((kLynxIsotCodeNormal << kLynxCMP0_FIELD3_MASKPhase) |
  7798.                                     (kLynxMatchIsochChannel << kLynxCMP0_FIELD2_MASKPhase));
  7799.             SynchronizeIO ();
  7800.         }
  7801.  
  7802.         // Set our data for port.
  7803.         pFWIMAllocateIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData =
  7804.             (UInt32) pLynxIsochPortData;
  7805.     }
  7806.  
  7807.     // Clean up on error.
  7808.     if (status != noErr)
  7809.     {
  7810.         if (pLynxIsochPortData != nil)
  7811.             _LynxFWIMReleaseIsochPort (pLynxFWIMData, pLynxIsochPortData);
  7812.     }
  7813.  
  7814.     // Complete FWIM command.
  7815.     pLynxFWIMData->pPendingFWIMCommand = nil;
  7816.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  7817.  
  7818.     // Return command acceptance.
  7819.     //zzz what if we call FWIMCommandIsComplete before returning this???
  7820.     //zzz well, it still works, but will it always?
  7821.     //zzz actually, when we switch to the dispatch table, each routine can return
  7822.     //zzz the appropriate acceptance, so don't worry about it for now.
  7823.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  7824.  
  7825.     return (status);
  7826. }
  7827.  
  7828.  
  7829. ////////////////////////////////////////////////////////////////////////////////
  7830. //
  7831. // LynxFWIMReleaseIsochPort
  7832. //
  7833. //   This routine will release resources allocated for the given isochronous
  7834. // channel.
  7835. //
  7836.  
  7837. static OSStatus LynxFWIMReleaseIsochPort(
  7838.     FWIMReleaseIsochPortParamsPtr
  7839.                                 pFWIMReleaseIsochPortParams,
  7840.     UInt32                        *pCommandAcceptance)
  7841. {
  7842.     FWIMCommandParamsPtr        pFWIMCommandParams;
  7843.     LynxFWIMDataPtr                pLynxFWIMData;
  7844.     LynxIsochPortDataPtr        pLynxIsochPortData;
  7845.     OSStatus                    status = noErr;
  7846.  
  7847. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMReleaseIsochPort");
  7848.  
  7849.     // Get our internal data.
  7850.     pFWIMCommandParams = &(pFWIMReleaseIsochPortParams->fwimCommandParams);
  7851.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  7852.  
  7853.     // Set pending command.
  7854.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMReleaseIsochPortParams;
  7855.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  7856.  
  7857.     // Get isoch port data.
  7858.     pLynxIsochPortData = (LynxIsochPortDataPtr)
  7859.         pFWIMReleaseIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData;
  7860.  
  7861.     // Release resources for isoch port.
  7862.     if (pLynxIsochPortData != nil)
  7863.         status = _LynxFWIMReleaseIsochPort (pLynxFWIMData, pLynxIsochPortData);
  7864.  
  7865.     // Complete FWIM command.
  7866.     pLynxFWIMData->pPendingFWIMCommand = nil;
  7867.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  7868.  
  7869.     // Return command acceptance.
  7870.     //zzz what if we call FWIMCommandIsComplete before returning this???
  7871.     //zzz well, it still works, but will it always?
  7872.     //zzz actually, when we switch to the dispatch table, each routine can return
  7873.     //zzz the appropriate acceptance, so don't worry about it for now.
  7874.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  7875.  
  7876.     return (status);
  7877. }
  7878.  
  7879.  
  7880. ////////////////////////////////////////////////////////////////////////////////
  7881. //
  7882. // _LynxFWIMReleaseIsochPort
  7883. //
  7884. //   This routine will release resources allocated for the given isochronous
  7885. // channel.
  7886. //
  7887.  
  7888. static OSStatus _LynxFWIMReleaseIsochPort(
  7889.     LynxFWIMDataPtr                pLynxFWIMData,
  7890.     LynxIsochPortDataPtr        pLynxIsochPortData)
  7891. {
  7892.     LynxDCLCompilerEngineDataPtr
  7893.                                 pLynxDCLCompilerEngineData = nil;
  7894.     OSStatus                    status = noErr;
  7895.  
  7896.     // If we're releasing a talking port, switch out of isoch transmit mode.
  7897.     //zzz what if this isn't the only talking port?
  7898.     if (pLynxIsochPortData->talking)
  7899.     {
  7900.         // Switch out of isochronous transmit mode.
  7901.         pLynxFWIMData->isochTransmitMode = false;
  7902.         LynxFWIMSetupFIFOs (pLynxFWIMData);
  7903.     }
  7904.     
  7905.     // Release DCL resources.
  7906.     if (pLynxIsochPortData->originalDCLProgramID != kInvalidDCLProgramID)
  7907.         status = FWReleaseDCLProgram (pLynxIsochPortData->originalDCLProgramID);
  7908.     
  7909.     // Deallocate isoch port data record.
  7910.     PoolDeallocate ((Ptr) pLynxIsochPortData);
  7911.     
  7912.     return (status);
  7913. }
  7914.  
  7915.  
  7916. ////////////////////////////////////////////////////////////////////////////////
  7917. //
  7918. // LynxFWIMStartIsochPort
  7919. //
  7920. //   Start up the given isochronous port on the given sync event using the
  7921. // given buffer.
  7922. //
  7923.  
  7924. static OSStatus LynxFWIMStartIsochPort(
  7925.     FWIMIsochPortControlParamsPtr
  7926.                                 pFWIMIsochPortControlParams,
  7927.     UInt32                        *pCommandAcceptance)
  7928. {
  7929.     FWIMCommandParamsPtr        pFWIMCommandParams;
  7930.     LynxFWIMDataPtr                pLynxFWIMData;
  7931.     LynxIsochPortDataPtr        pLynxIsochPortData;
  7932.     OSStatus                    status = noErr;
  7933.  
  7934. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMStartIsochPort");
  7935.  
  7936.     // Get our internal data.
  7937.     pFWIMCommandParams = &(pFWIMIsochPortControlParams->fwimCommandParams);
  7938.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  7939.  
  7940.     // Set pending command.
  7941.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
  7942.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  7943.  
  7944.     // Get isoch port data.
  7945.     pLynxIsochPortData = (LynxIsochPortDataPtr)
  7946.         pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
  7947.  
  7948.     // Start DCL program.
  7949.     if (status == noErr)
  7950.         status = FWStartDCLProgram (pLynxIsochPortData->originalDCLProgramID);
  7951.  
  7952.     // Finish up command.
  7953.     pLynxFWIMData->pPendingFWIMCommand = nil;
  7954.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  7955.  
  7956.     // Return command acceptance.
  7957.     //zzz what if we call FWIMCommandIsComplete before returning this???
  7958.     //zzz well, it still works, but will it always?
  7959.     //zzz actually, when we switch to the dispatch table, each routine can return
  7960.     //zzz the appropriate acceptance, so don't worry about it for now.
  7961.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  7962.  
  7963.     return (status);
  7964. }
  7965.  
  7966.  
  7967. ////////////////////////////////////////////////////////////////////////////////
  7968. //
  7969. // LynxFWIMStopIsochPort
  7970. //
  7971. //   Stop the given isochronous port on the given sync event.
  7972. //
  7973.  
  7974. static OSStatus LynxFWIMStopIsochPort(
  7975.     FWIMIsochPortControlParamsPtr
  7976.                                 pFWIMIsochPortControlParams,
  7977.     UInt32                        *pCommandAcceptance)
  7978. {
  7979.     FWIMCommandParamsPtr        pFWIMCommandParams;
  7980.     LynxFWIMDataPtr                pLynxFWIMData;
  7981.     LynxIsochPortDataPtr        pLynxIsochPortData;
  7982.     OSStatus                    status = noErr;
  7983.  
  7984. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMStopIsochPort");
  7985.  
  7986.     // Get our internal data.
  7987.     pFWIMCommandParams = &(pFWIMIsochPortControlParams->fwimCommandParams);
  7988.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  7989.  
  7990.     // Set pending command.
  7991.     pLynxFWIMData->pPendingFWIMCommand = (FWIMCommandParamsPtr) pFWIMIsochPortControlParams;
  7992.     pLynxFWIMData->pendingFWIMCommandStatus = kLynxPendingFWIMCommandBusy;
  7993.  
  7994.     // Get isoch port data.
  7995.     pLynxIsochPortData = (LynxIsochPortDataPtr)
  7996.         pFWIMIsochPortControlParams->fwimIsochPortCommandParams.fwimIsochPortData;
  7997.  
  7998.     // Stop DCL program.
  7999.     if (status == noErr)
  8000.         status = FWStopDCLProgram (pLynxIsochPortData->originalDCLProgramID);
  8001.  
  8002.     // Finish up command.
  8003.     pLynxFWIMData->pPendingFWIMCommand = nil;
  8004.     status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  8005.  
  8006.     // Return command acceptance.
  8007.     //zzz what if we call FWIMCommandIsComplete before returning this???
  8008.     //zzz well, it still works, but will it always?
  8009.     //zzz actually, when we switch to the dispatch table, each routine can return
  8010.     //zzz the appropriate acceptance, so don't worry about it for now.
  8011.     *pCommandAcceptance = kFWIMCommandAcceptNoMore;
  8012.  
  8013.     return (status);
  8014. }
  8015.  
  8016.  
  8017. ////////////////////////////////////////////////////////////////////////////////
  8018. //
  8019. // LynxFWIMStartTalkingDCLProgram
  8020. //
  8021. //   This routine starts running the given DCL program.
  8022. //
  8023.  
  8024. static OSStatus LynxFWIMStartTalkingDCLProgram(
  8025.     DCLProgramID                dclProgramID)
  8026. {
  8027.     LynxDCLCompilerEngineDataPtr
  8028.                                 pLynxDCLCompilerEngineData;
  8029.     LynxFWIMDataPtr                pLynxFWIMData;
  8030.     LynxRegistersPtr            pLynxRegs;
  8031.     OSStatus                    status = noErr;
  8032.  
  8033.     // Get our engine data and FWIM data.
  8034.     status = FWGetDCLProgramEngineData
  8035.                 (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
  8036.     if (status == noErr)
  8037.         pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
  8038.  
  8039.     // Get base address of Lynx registers.
  8040.     if (status == noErr)
  8041.         pLynxRegs = pLynxFWIMData->pLynxRegisters;
  8042.  
  8043.     // Start the DMA engine.
  8044.     if (status == noErr)
  8045.     {
  8046.         // We'll report statistics at the end of the transmit, if FireBug enabled.
  8047.         pLynxRegs->fifoOverUnderErrorCounters = EndianSwapImm32Bit (0);
  8048.         
  8049.         // Load a physical address
  8050.         pLynxRegs->dmaChannel[kIsochTransmitDMA].curPCLAddr =
  8051.             EndianSwap32Bit ((UInt32) pLynxDCLCompilerEngineData->pStartPCL->refCon);
  8052.         SynchronizeIO ();
  8053.  
  8054.         // Set CH ENA and Link bits to enable DMA.
  8055.         pLynxRegs->dmaChannel[kIsochTransmitDMA].control =
  8056.             EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  8057.         SynchronizeIO ();
  8058.         
  8059.         // In rare cases, we might not start transmitting.  Somehow the FIFO gets jammed,
  8060.         // even though we flush it before and after iso transmit programs run.  I have
  8061.         // only seen this in pre-revA parts, so maybe it's one of the errata items.
  8062.     }
  8063.  
  8064.     return (status);
  8065. }
  8066.  
  8067.  
  8068. ////////////////////////////////////////////////////////////////////////////////
  8069. //
  8070. // LynxFWIMStartListeningDCLProgram
  8071. //
  8072. //   This routine starts running the given DCL program.
  8073. //
  8074.  
  8075. static OSStatus LynxFWIMStartListeningDCLProgram(
  8076.     DCLProgramID                dclProgramID)
  8077. {
  8078.     LynxDCLCompilerEngineDataPtr
  8079.                                 pLynxDCLCompilerEngineData;
  8080.     LynxFWIMDataPtr                pLynxFWIMData;
  8081.     LynxRegistersPtr            pLynxRegs;
  8082.     OSStatus                    status = noErr;
  8083.  
  8084.     // Get our engine data and FWIM data.
  8085.     status = FWGetDCLProgramEngineData
  8086.                 (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
  8087.     if (status == noErr)
  8088.         pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
  8089.  
  8090.     // Get base address of Lynx registers.
  8091.     if (status == noErr)
  8092.         pLynxRegs = pLynxFWIMData->pLynxRegisters;
  8093.  
  8094.     // Start the DMA engine.
  8095.     if (status == noErr)
  8096.     {
  8097.         // Load a physical address
  8098.         pLynxRegs->dmaChannel[kIsochReceiveDMA].curPCLAddr =
  8099.             EndianSwap32Bit ((UInt32) pLynxDCLCompilerEngineData->pStartPCL->refCon);
  8100.         SynchronizeIO ();
  8101.  
  8102.         // Set ready, CH ENA, and Link bits to enable DMA.
  8103.         pLynxRegs->dmaChannel[kIsochReceiveDMA].ready =
  8104.             EndianSwapImm32Bit (kLynxDMAReadyCONDITION);
  8105.         SynchronizeIO ();
  8106.  
  8107.         pLynxRegs->dmaChannel[kIsochReceiveDMA].control =
  8108.             EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  8109.         SynchronizeIO ();
  8110.         
  8111.         // Enable receive comparator.
  8112.         pLynxRegs->dmaComparator[kIsochReceiveDMA].mask1 =
  8113.             EndianSwapImm32Bit (kLynxEN_CH_COMPARE);
  8114.         SynchronizeIO ();
  8115.     }
  8116.  
  8117.     return (status);
  8118. }
  8119.  
  8120.  
  8121. ////////////////////////////////////////////////////////////////////////////////
  8122. //
  8123. // LynxFWIMStopTalkingDCLProgram
  8124. //
  8125. //   This routine stops running the given DCL program.
  8126. //
  8127.  
  8128. static OSStatus LynxFWIMStopTalkingDCLProgram(
  8129.     DCLProgramID                dclProgramID)
  8130. {
  8131.     LynxDCLCompilerEngineDataPtr
  8132.                                 pLynxDCLCompilerEngineData;
  8133.     LynxFWIMDataPtr                pLynxFWIMData;
  8134.     LynxRegistersPtr            pLynxRegs;
  8135.     UInt32                        linkFIFO, pciFIFO, waitForFIFO;
  8136.     OSStatus                    status = noErr;
  8137.  
  8138.     // Get our engine data and FWIM data.
  8139.     status = FWGetDCLProgramEngineData
  8140.                 (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
  8141.     if (status == noErr)
  8142.         pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
  8143.  
  8144.     // Get base address of Lynx registers.
  8145.     if (status == noErr)
  8146.         pLynxRegs = pLynxFWIMData->pLynxRegisters;
  8147.  
  8148.     // Stop the DMA engine.
  8149.     if (status == noErr)
  8150.     {
  8151.         //zzz Read quad out of ITF FIFO to clear underflow jams.
  8152.         pLynxFWIMData->bitBucket = pLynxRegs->itfPopPush0;
  8153.         SynchronizeIO ();
  8154.  
  8155.         // Clear the Ready bit.  Each transmit PCL has a wait-for-ready,
  8156.         // so the DMA will pause before the start of the next packet.
  8157.         pLynxRegs->dmaChannel[kIsochTransmitDMA].ready = EndianSwapImm32Bit (0);
  8158.         SynchronizeIO ();
  8159.                 
  8160.         // In very unusual circumstances, it could be a long time until the DMA
  8161.         // stops.  For example, we could have preloaded 30 or 40 cycles of tiny
  8162.         // packets (say, header only with zero payload) and now we're trying to
  8163.         // send one really big packet (larger than the FIFO).  Because the IT DMA
  8164.         // tries to work ahead, it will be loading that big packet a little at a
  8165.         // time, as room becomes available in the FIFO.  That could take 30 or 40
  8166.         // cycles before the DMA finishes the current command and can pause.
  8167.  
  8168.         // To be sure the pause really took effect, wait here until the IT FIFO
  8169.         // is empty.  If the FIFO is full because we can't transmit, this would
  8170.         // wait forever, so also bail out if we wait too long.
  8171.         // zzz should use real time, not one million loops.
  8172.  
  8173.         // A better way to do this would be to arrange for an interrupt.
  8174.         // But that's complicated - one would have to rewrite part of the
  8175.         // PCL to interrupt and halt, then resume it, then exit here, then
  8176.         // take the interrupt, then clean up the PCL (which might be reused later).
  8177.  
  8178.         waitForFIFO = 1000000;
  8179.         while (waitForFIFO)
  8180.         {
  8181.             waitForFIFO--;
  8182.             linkFIFO = EndianSwap32Bit (pLynxRegs->linkFifoPort);
  8183.             pciFIFO = EndianSwap32Bit (pLynxRegs->linkFifoPort);
  8184.             SynchronizeIO ();
  8185.             
  8186.             // The mask checks both the FIFO index and the "wrap-around" bit.
  8187.             // They both have to be equal if the FIFO is empty.  If they are
  8188.             // equal, make sure they are also unchanged.  If either of them
  8189.             // "moved", try again.
  8190.             
  8191.             if ((linkFIFO && 0x04ff0000) == (pciFIFO && 0x04ff0000))
  8192.             {
  8193.                 if ((linkFIFO == EndianSwap32Bit (pLynxRegs->linkFifoPort)) &&
  8194.                     (pciFIFO == EndianSwap32Bit (pLynxRegs->linkFifoPort)))
  8195.                     waitForFIFO = 0;
  8196.             }
  8197.         }
  8198.         
  8199.         // DMA must be idle by now, so it's safe to turn it off.
  8200.         
  8201.         pLynxRegs->dmaChannel[kIsochTransmitDMA].control &=
  8202.             ~EndianSwapImm32Bit (kLynxDMA_CH_ENA | kLynxDMA_LINK);
  8203.         SynchronizeIO ();
  8204.         
  8205. #ifdef LynxFireBug
  8206. {
  8207.     UInt32 temp = EndianSwap32Bit (pLynxRegs->fifoOverUnderErrorCounters);
  8208.     sprintf (fireBug, "LynxFWIM:  FIFO stats during iso tx:  ITF_UNDER %ld,  ATF_UNDER %ld,  GRF_OVER %ld",
  8209.              (temp >> 16) & 0xff, (temp >> 8) & 0xff, temp & 0xff);
  8210.     LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
  8211. }
  8212. #endif
  8213.     }
  8214.  
  8215.     return (status);
  8216. }
  8217.  
  8218.  
  8219. ////////////////////////////////////////////////////////////////////////////////
  8220. //
  8221. // LynxFWIMStopListeningDCLProgram
  8222. //
  8223. //   This routine stops running the given DCL program.
  8224. //
  8225.  
  8226. static OSStatus LynxFWIMStopListeningDCLProgram(
  8227.     DCLProgramID                dclProgramID)
  8228. {
  8229.     LynxDCLCompilerEngineDataPtr
  8230.                                 pLynxDCLCompilerEngineData;
  8231.     LynxFWIMDataPtr                pLynxFWIMData;
  8232.     LynxRegistersPtr            pLynxRegs;
  8233.     OSStatus                    status = noErr;
  8234.  
  8235.     // Get our engine data and FWIM data.
  8236.     status = FWGetDCLProgramEngineData
  8237.                 (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
  8238.     if (status == noErr)
  8239.         pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
  8240.  
  8241.     // Get base address of Lynx registers.
  8242.     if (status == noErr)
  8243.         pLynxRegs = pLynxFWIMData->pLynxRegisters;
  8244.  
  8245.     // Stop the DMA engine.
  8246.     if (status == noErr)
  8247.     {
  8248.         // Disable channel comparator.
  8249.         //zzz need way to bit bucket any remaining packets in FIFO
  8250.         pLynxRegs->dmaComparator[kIsochReceiveDMA].mask1 = 0;
  8251.         SynchronizeIO ();
  8252.     }
  8253.  
  8254.     return (status);
  8255. }
  8256.  
  8257.  
  8258. ////////////////////////////////////////////////////////////////////////////////
  8259. //
  8260. // LynxFWIMReleaseDCLProgram
  8261. //
  8262. //   This routine releases the resources allocated for the given DCL program.
  8263. //
  8264.  
  8265. static OSStatus LynxFWIMReleaseDCLProgram(
  8266.     DCLProgramID                dclProgramID)
  8267. {
  8268.     LynxDCLCompilerEngineDataPtr
  8269.                                 pLynxDCLCompilerEngineData;
  8270.     LynxFWIMDataPtr                pLynxFWIMData;
  8271.     OSStatus                    status = noErr;
  8272.  
  8273.     // Get our engine data and FWIM data.
  8274.     status = FWGetDCLProgramEngineData
  8275.                 (dclProgramID, (UInt32 *) &pLynxDCLCompilerEngineData);
  8276.     if (status == noErr)
  8277.         pLynxFWIMData = pLynxDCLCompilerEngineData->pLynxFWIMData;
  8278.  
  8279.     if (status == noErr)
  8280.     {
  8281.         // Deallocate PCL pools.
  8282.         if (pLynxDCLCompilerEngineData->pLynxPCLPoolDataList != nil)
  8283.         {
  8284.             LynxFWIMDeallocatePCLPools
  8285.                 (pLynxDCLCompilerEngineData->pLynxPCLPoolDataList);
  8286.         }
  8287.         
  8288.         // Release all VM resources
  8289.         // Kind of a hack - we set this to -1 if the PrepareMemoryForIO failed:
  8290.         if (pLynxDCLCompilerEngineData->ioPrep.mappingEntryCount != -1)
  8291.         {
  8292.             status = CheckpointIO (pLynxDCLCompilerEngineData->ioPrep.preparationID, kNilOptions);
  8293.             if (status != noErr)
  8294.             {
  8295.                 sprintf (debugStr, "DCL data CheckpointIO status %ld",
  8296.                          (long) status);
  8297.                 FWDebugStr ((ConstStr255Param) c2pstr (debugStr));
  8298.             }
  8299.             PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData->ioPrep.rangeInfo.multipleRanges.rangeTable);
  8300.             PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData->ioPrep.physicalMapping);
  8301.         }
  8302.         
  8303.         // Deallocate engine data.
  8304.         PoolDeallocate ((Ptr) pLynxDCLCompilerEngineData);
  8305.     }
  8306.     
  8307.     return (status);
  8308. }
  8309.  
  8310.  
  8311. ////////////////////////////////////////////////////////////////////////////////
  8312. //
  8313. // LynxFWIMReadRequestTimeoutHandler
  8314. //
  8315. //   This proc will retry a transaction if any more retries are specified.
  8316. //
  8317.  
  8318. static OSStatus    LynxFWIMReadRequestTimeoutHandler(
  8319.     void                        *p1,
  8320.     void                        *p2)
  8321. {
  8322.     FWIMCommandParamsPtr        pFWIMCommandParams;
  8323.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams =
  8324.                                     (FWIMAsynchCommandParamsPtr) p1;
  8325.     LynxFWIMDataPtr                pLynxFWIMData; 
  8326.     UInt32                        commandAcceptance;
  8327.     Boolean                        commandBusy;
  8328.     OSStatus                    pendingFWIMCommandStatus,
  8329.                                 status = noErr;
  8330.  
  8331. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMReadRequestTimeoutHandler");
  8332.  
  8333.     // Get our internal data.
  8334.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  8335.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  8336.     pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
  8337.  
  8338.     // Note that timer went off.
  8339.     pLynxFWIMData->requestTimeoutTimerSet = false;
  8340.  
  8341.     // Check if command is still busy.
  8342.     if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
  8343.     {
  8344.         commandBusy = true;
  8345.     }
  8346.     else
  8347.     {
  8348.         commandBusy = false;
  8349.         status = pendingFWIMCommandStatus;
  8350.     }
  8351.  
  8352.     // Retry if there are more retries left, otherwise return with timeout
  8353.     // status.
  8354.     if (commandBusy)
  8355.     {
  8356.         if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
  8357.         {
  8358.             status = LynxFWIMRead (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
  8359.         }
  8360.         else
  8361.         {
  8362.             status = timeoutErr;
  8363.         }
  8364.  
  8365.         if (status != noErr)
  8366.             commandBusy = false;
  8367.     }
  8368.  
  8369.     // Complete command if it's no longer busy.
  8370.     if (!commandBusy)
  8371.     {
  8372.         pLynxFWIMData->pPendingFWIMCommand = nil;
  8373.         status = FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  8374.     }
  8375.  
  8376.     return (status);
  8377. }
  8378.  
  8379.  
  8380. ////////////////////////////////////////////////////////////////////////////////
  8381. //
  8382. // LynxFWIMWriteRequestTimeoutHandler
  8383. //
  8384. //   This proc will retry a transaction if any more retries are specified.
  8385. //zzz Only need this until reset code completes commands manually.
  8386. //zzz need locking mechanism between this routine and the ack int routine.
  8387. //
  8388. // Note - presently unused (not set in LynxFWIMWrite)
  8389.  
  8390. static OSStatus    LynxFWIMWriteRequestTimeoutHandler(
  8391.     void                        *p1,
  8392.     void                        *p2)
  8393. {
  8394.     FWIMCommandParamsPtr        pFWIMCommandParams;
  8395.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams =
  8396.                                     (FWIMAsynchCommandParamsPtr) p1;
  8397.     LynxFWIMDataPtr                pLynxFWIMData; 
  8398.     LynxRegistersPtr            pLynxRegs;
  8399.     Boolean                        commandBusy;
  8400.     OSStatus                    pendingFWIMCommandStatus,
  8401.                                 status = noErr;
  8402.  
  8403. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMWriteRequestTimeoutHandler");
  8404.  
  8405.     // Get our internal data.
  8406.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  8407.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  8408.     pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
  8409.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  8410.  
  8411.     // Note that timer went off.
  8412.     pLynxFWIMData->requestTimeoutTimerSet = false;
  8413.  
  8414.     // Check if command is still busy.
  8415.     if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
  8416.     {
  8417.         commandBusy = true;
  8418.     }
  8419.     else
  8420.     {
  8421.         commandBusy = false;
  8422.         status = pendingFWIMCommandStatus;
  8423.     }
  8424.  
  8425.     // Check if ack code indicates a completed transfer.  Retry if it doesn't.
  8426.     if (commandBusy)
  8427.     {
  8428. // NYI
  8429. // Works differently in Lynx - look in DMA/PCL status
  8430.         FWDebugStr ((ConstStr255Param) "\pLynxFWIMWriteRequestTimeoutHandler - NYI ###");
  8431. #if 0
  8432.         nodeAddress = EndianSwap32Bit (pLinkRegs->nodeAddress);
  8433.         ackCode =
  8434.             (nodeAddress & kTINodeAddressATAck) >> kTINodeAddressATAckPhase;
  8435.         if (ackCode == kFWAckComplete)
  8436.         {
  8437.             commandBusy = false;
  8438.             status = noErr;
  8439.         }
  8440.         else
  8441.         {
  8442.             if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
  8443.             {
  8444.                 status = LynxFWIMWrite (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
  8445.             }
  8446.             else
  8447.             {
  8448.                 status = timeoutErr;
  8449.             }
  8450.  
  8451.             if (status != noErr)
  8452.                 commandBusy = false;
  8453.         }
  8454. #endif
  8455.     }
  8456.  
  8457.     // Complete command if it's no longer busy.
  8458.     if (!commandBusy)
  8459.     {
  8460.         pLynxFWIMData->pPendingFWIMCommand = nil;
  8461.         status =
  8462.             FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  8463.     }
  8464.  
  8465.     return (status);
  8466. }
  8467.  
  8468.  
  8469. ////////////////////////////////////////////////////////////////////////////////
  8470. //
  8471. // LynxFWIMLockRequestTimeoutHandler
  8472. //
  8473. //   This proc will retry a transaction if any more retries are specified.
  8474. //zzz need to check if command is still busy.
  8475. // NYI - Never tested for Lynx
  8476. //
  8477.  
  8478. static OSStatus    LynxFWIMLockRequestTimeoutHandler(
  8479.     void                        *p1,
  8480.     void                        *p2)
  8481. {
  8482.     FWIMCommandParamsPtr        pFWIMCommandParams;
  8483.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams =
  8484.                                     (FWIMAsynchCommandParamsPtr) p1;
  8485.     LynxFWIMDataPtr                pLynxFWIMData; 
  8486.     UInt32                        commandAcceptance;
  8487.     Boolean                        commandBusy;
  8488.     OSStatus                    pendingFWIMCommandStatus,
  8489.                                 status = noErr;
  8490.  
  8491. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMLockRequestTimeoutHandler");
  8492.  
  8493.     // Get our internal data.
  8494.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  8495.     pLynxFWIMData = (LynxFWIMDataPtr) pFWIMCommandParams->fwimSpecificData;
  8496.     pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
  8497.  
  8498.     // Note that timer went off.
  8499.     pLynxFWIMData->requestTimeoutTimerSet = false;
  8500.  
  8501.     // Check if command is still busy.
  8502.     if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
  8503.     {
  8504.         commandBusy = true;
  8505.     }
  8506.     else
  8507.     {
  8508.         commandBusy = false;
  8509.         status = pendingFWIMCommandStatus;
  8510.     }
  8511.  
  8512.     // Retry if there are more retries left, otherwise return with timeout
  8513.     // status.
  8514.     if (commandBusy)
  8515.     {
  8516.         if (((SInt8) pFWIMAsynchCommandParams->numRetries--) > 0)
  8517.         {
  8518.             status = LynxFWIMLock (pFWIMAsynchCommandParams, &commandAcceptance);//zzz shouldn't have to pass in commandAcceptance
  8519.         }
  8520.         else
  8521.         {
  8522.             status = timeoutErr;
  8523.         }
  8524.  
  8525.         if (status != noErr)
  8526.             commandBusy = false;
  8527.     }
  8528.  
  8529.     // Complete command if it's no longer busy.
  8530.     if (!commandBusy)
  8531.     {
  8532.         pLynxFWIMData->pPendingFWIMCommand = nil;
  8533.         status =
  8534.             FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID, status);
  8535.     }
  8536.  
  8537.     return (status);
  8538. }
  8539.  
  8540.  
  8541. ////////////////////////////////////////////////////////////////////////////////
  8542. //
  8543. // LynxFWIMDMAAsyncPCLDeferredTask
  8544. //
  8545. //   Dispatches self-ID and async packets after DMA is finished
  8546. //
  8547.  
  8548. static void    LynxFWIMDMAAsyncPCLDeferredTask(
  8549.     void                        *p1,
  8550.     void                        *p2)
  8551. {
  8552.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  8553.     LynxPCLPtr                    pPCL, pSkimPCL, pLastSelfIDsPCL;
  8554.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData, pSkimPCLData;
  8555.     UInt32                        pclStatus, skimStatus;
  8556.     UInt32                        packetSize, skimSize;
  8557.     Ptr                            packetBuffer;
  8558.     UInt32                        quad0, quad1;
  8559.     Boolean                        skimDone;
  8560.     UInt32                        skipCount;
  8561.     static UInt32                skipTotal = 0;
  8562.     OSStatus                    status = noErr;
  8563.  
  8564.     // Asynch receive DT no longer scheduled.
  8565.     pLynxFWIMData->asyncReceiveDTScheduled = false;
  8566.  
  8567.     // This is part of a temporary hack.
  8568.     // Within 50ms after a bus reset, don't accept any packets.
  8569.     // We'll get called again after these flags are cleared.
  8570.     
  8571.     if ((pLynxFWIMData->delayedResetTimerSet) || (pLynxFWIMData->busResetDTScheduled))
  8572.         return;
  8573.  
  8574.     // Get next PCL to process and its data.
  8575.     pPCL = pLynxFWIMData->pNextAsyncPCL;
  8576.     if (pPCL != nil)
  8577.     {
  8578.         pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  8579.         pclStatus = EndianSwap32Bit (pPCL->status);
  8580.     }
  8581.     else
  8582.     {
  8583.         pclStatus = kLynxInvalidStatus;
  8584.     }
  8585.  
  8586.     // Process all PCLs with data.
  8587.     while (pclStatus & kLynxPktCmp)
  8588.     {
  8589.         // Set next PCL to process.
  8590.         pLynxFWIMData->pNextAsyncPCL = pLynxAsyncRxPCLData->pNextPCL;
  8591.  
  8592.         // If this packet is self-IDs, and we are running behind, then
  8593.         // there could be *another* packet with self-IDs waiting too.
  8594.         // In that case, we can avoid a bunch of PHY register reads
  8595.         // and other work by just skipping to the last available self-IDs.
  8596.         // The skipped packets can't contain any responses we want, and
  8597.         // we will be unable to reply to any requests during that period,
  8598.         // so we can safely dispose of all of the packets.
  8599.         
  8600.         // In theory it is possible for someone to have sent us a write
  8601.         // request to which we sent ack_complete.  However, because this
  8602.         // write request was sent after a bus reset, and before we had ever
  8603.         // identified ourselves, the sender has no way to know who we are.
  8604.         // So we can safely ignore such a request even if we said ack_complete.
  8605.         
  8606.         // zzz However, if someone sent a *broadcast* write, they might reasonably
  8607.         // except us to (try to) receive it.  If we find a broadcast write while
  8608.         // scanning ahead, we really ought to stop scanning at that point.
  8609.         
  8610.         // Process packet if it had no errors.  Otherwise recycle PCL.
  8611.         if (!(pclStatus & (kLynxMstErr | kLynxPktErr)))
  8612.         {
  8613.             // Get packet buffer and length.
  8614.             packetBuffer = pLynxAsyncRxPCLData->packetBuffer;
  8615.             packetSize = (pclStatus & kLynxTransferredCount) >>
  8616.                          kLynxTransferredCountPhase;
  8617.  
  8618.             // Get first two quads.
  8619.             quad0 = ((UInt32 *) packetBuffer)[0];
  8620.             quad1 = ((UInt32 *) packetBuffer)[1];
  8621.         
  8622.             // If length is zero or first quad is inverse of second quad, assume self-IDs
  8623.             if ((packetSize == 0) || (quad0 == ~quad1))
  8624.             {
  8625.                 // Self-IDs
  8626.                 pLastSelfIDsPCL = pSkimPCL = pPCL;
  8627.                 pSkimPCLData = (LynxAsyncRxPCLDataPtr) pSkimPCL->refCon;
  8628.                 skimStatus = EndianSwap32Bit (pPCL->status);
  8629.                 skimDone = false;
  8630.                 
  8631.                 while (skimDone == false)
  8632.                 {
  8633.                     // Move to next PCL
  8634.                     pSkimPCL = pSkimPCLData->pNextPCL;
  8635.                     if (pSkimPCL == nil)
  8636.                     {
  8637.                         // Hit the end of the list
  8638.                         skimDone = true;
  8639.                     }
  8640.                     else
  8641.                     {
  8642.                         pSkimPCLData = (LynxAsyncRxPCLDataPtr) pSkimPCL->refCon;
  8643.                         skimStatus = EndianSwap32Bit (pSkimPCL->status);
  8644.                     }
  8645.                     
  8646.                     if ((skimDone == false) && (skimStatus & kLynxPktCmp))
  8647.                     {
  8648.                         // pSkimPCL points to a PCL that has been executed
  8649.                         // If this one had an error, just keep looking.
  8650.                         if (!(skimStatus & (kLynxMstErr | kLynxPktErr)))
  8651.                         {
  8652.                             // Get packet buffer and length.
  8653.                             skimSize = (skimStatus & kLynxTransferredCount) >>
  8654.                                          kLynxTransferredCountPhase;
  8655.                 
  8656.                             // Get first two quads.
  8657.                             quad0 = ((UInt32 *) pSkimPCLData->packetBuffer)[0];
  8658.                             quad1 = ((UInt32 *) pSkimPCLData->packetBuffer)[1];
  8659.                         
  8660.                             // If length is zero or first quad is inverse of second quad, assume self-IDs
  8661.                             if ((skimSize == 0) || (quad0 == ~quad1))
  8662.                             {
  8663.                                 // This is the latest point we can skip ahead to (so far)
  8664.                                 pLastSelfIDsPCL = pSkimPCL;
  8665.                             }
  8666.                         }
  8667.                     }
  8668.                     else    // ran out of places to look
  8669.                     {
  8670.                         skimDone = true;
  8671.                     }
  8672.                 }
  8673.                 
  8674.                 if (pLastSelfIDsPCL != pPCL)
  8675.                 {
  8676.                     // recycle skipped PCLs and
  8677.                     // set up for alternate
  8678.                     
  8679.                     skipCount = 0;
  8680.                     while (pPCL != pLastSelfIDsPCL)
  8681.                     {
  8682.                         // Add PCL back to active list.
  8683.                         pSkimPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  8684.                         pSkimPCL = pSkimPCLData->pNextPCL;
  8685.                         LynxFWIMAddAsyncRxPCL (pPCL);
  8686.                         pPCL = pSkimPCL;
  8687.                         skipCount++;
  8688.                         skipTotal++;
  8689.                     }
  8690.                     
  8691.                     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  8692.                     pLynxFWIMData->pNextAsyncPCL = pLynxAsyncRxPCLData->pNextPCL;
  8693.                     pclStatus = EndianSwap32Bit (pPCL->status);
  8694.                     packetBuffer = pLynxAsyncRxPCLData->packetBuffer;
  8695.                     packetSize = (pclStatus & kLynxTransferredCount) >>
  8696.                                  kLynxTransferredCountPhase;
  8697.                     
  8698.                     //sprintf (fireBug, "LynxFWIM: Skipped %ld useless packets [%ld total]",
  8699.                     //         (long) skipCount, (long) skipTotal);
  8700.                     //LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
  8701.                 }
  8702.             }
  8703.  
  8704.             // Process packet.
  8705.             LynxFWIMProcessPacket (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  8706.         }
  8707.         else
  8708.         {
  8709.             // Add PCL back to active list.
  8710.             LynxFWIMAddAsyncRxPCL (pPCL);
  8711.         }
  8712.  
  8713.         // Process next PCL.
  8714.         pPCL = pLynxFWIMData->pNextAsyncPCL;
  8715.         if (pPCL != nil)
  8716.         {
  8717.             pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  8718.             pclStatus = EndianSwap32Bit (pPCL->status);
  8719.         }
  8720.         else
  8721.         {
  8722.             pclStatus = kLynxInvalidStatus;
  8723.         }
  8724.     }
  8725. }
  8726.  
  8727.  
  8728. ////////////////////////////////////////////////////////////////////////////////
  8729. //
  8730. // LynxFWIMDMAIsochReceivePCLDeferredTask
  8731. //
  8732. //   Handles PCL interrupts for isochronous receive.
  8733. //
  8734.  
  8735. static void    LynxFWIMDMAIsochReceivePCLDeferredTask(
  8736.     void                        *p1,
  8737.     void                        *p2)
  8738. {
  8739.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  8740.     LynxIsochPortDataPtr        pLynxIsochPortData;
  8741.     static LynxDCLProgramInterruptQueueElementPtr
  8742.                                 pDCLInterruptList[100];//zzz fixed for now, dynamically allocate later.
  8743.     LynxDCLProgramInterruptQueueElementPtr
  8744.                                 pDCLInterrupt,
  8745.                                 pPrevDCLInterrupt;
  8746.     DCLCommandPtr                pDCLCommand;
  8747.     DCLCallProcPtr                pDCLCallProc;
  8748.     DCLUpdateDCLListPtr            pDCLUpdateDCLList;
  8749.     UInt32                        numInterrupts;
  8750.     OSStatus                    status = noErr;
  8751.  
  8752.     // Isoch receive DT no longer scheduled.
  8753.     pLynxFWIMData->isochReceiveDTScheduled = false;
  8754.  
  8755.     // Get isoch port data.
  8756.     pLynxIsochPortData = pLynxFWIMData->lynxIsochPortDataList[kIsochReceiveDMA];
  8757.  
  8758.     // Get and clear interrupt queue tail.
  8759.     pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[kIsochReceiveDMA];
  8760.     while (!CompareAndSwap
  8761.                 ((UInt32) pDCLInterrupt,
  8762.                  nil,
  8763.                  (UInt32 *) &(pLynxFWIMData->pDCLInterruptTail[kIsochReceiveDMA])))
  8764.     {
  8765.         pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[kIsochReceiveDMA];
  8766.     }
  8767.  
  8768.     // Build interrupt list and clear interrupts.
  8769.     numInterrupts = 0;
  8770.     while ((pDCLInterrupt != nil) && (numInterrupts < 10))
  8771.     {
  8772.         pDCLInterruptList[numInterrupts] = pDCLInterrupt;
  8773.         pPrevDCLInterrupt = pDCLInterrupt->pPrevDCLInterrupt;
  8774.         pDCLInterrupt->pPrevDCLInterrupt = nil;
  8775.         numInterrupts++;
  8776.  
  8777.         pDCLInterrupt = pPrevDCLInterrupt;
  8778.     }
  8779.  
  8780.     // Run through interrupt queue.
  8781.     while (numInterrupts--)
  8782.     {
  8783.         // Get DCL command that caused interrupt.
  8784.         pDCLCommand = pDCLInterruptList[numInterrupts]->pDCLCommand;
  8785.  
  8786.         // Dispatch off of opcode.
  8787.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  8788.         {
  8789.             case kDCLCallProcOp :
  8790.                 // Call the proc.
  8791.                 pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
  8792.                 FWCallDCLCallProc (pLynxIsochPortData->dclProgramID, pDCLCallProc);
  8793.                 break;
  8794.  
  8795.             case kDCLUpdateDCLListOp :
  8796.                 // Update the DCL list.
  8797.                 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
  8798.                 LynxFWIMDCLCompilerUpdateNotification (pLynxIsochPortData->dclProgramID,
  8799.                                                        pDCLUpdateDCLList->dclCommandList,
  8800.                                                        pDCLUpdateDCLList->numDCLCommands);
  8801.                 break;
  8802.  
  8803.             default :
  8804.                 break;
  8805.         }
  8806.     }
  8807. }
  8808.  
  8809.  
  8810. ////////////////////////////////////////////////////////////////////////////////
  8811. //
  8812. // LynxFWIMDMAIsochTransmitDeferredTask
  8813. //
  8814. //   Handles PCL interrupts for isochronous transmit.
  8815. //
  8816.  
  8817. static void    LynxFWIMDMAIsochTransmitDeferredTask(
  8818.     void                        *p1,
  8819.     void                        *p2)
  8820. {
  8821.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  8822.     LynxIsochPortDataPtr        pLynxIsochPortData;
  8823.     static LynxDCLProgramInterruptQueueElementPtr
  8824.                                 pDCLInterruptList[100];//zzz fixed for now, dynamically allocate later.
  8825.     LynxDCLProgramInterruptQueueElementPtr
  8826.                                 pDCLInterrupt,
  8827.                                 pPrevDCLInterrupt;
  8828.     DCLCommandPtr                pDCLCommand;
  8829.     DCLCallProcPtr                pDCLCallProc;
  8830.     DCLUpdateDCLListPtr            pDCLUpdateDCLList;
  8831.     UInt32                        numInterrupts;
  8832.     OSStatus                    status = noErr;
  8833.  
  8834.     // Isoch transmit DT no longer scheduled.
  8835.     pLynxFWIMData->isochTransmitDTScheduled = false;
  8836.  
  8837.     // Get isoch port data.
  8838.     pLynxIsochPortData = pLynxFWIMData->lynxIsochPortDataList[kIsochTransmitDMA];
  8839.  
  8840.     // Get and clear interrupt queue tail.
  8841.     pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[kIsochTransmitDMA];
  8842.     while (!CompareAndSwap
  8843.                 ((UInt32) pDCLInterrupt,
  8844.                  nil,
  8845.                  (UInt32 *) &(pLynxFWIMData->pDCLInterruptTail[kIsochTransmitDMA])))
  8846.     {
  8847.         pDCLInterrupt = pLynxFWIMData->pDCLInterruptTail[kIsochTransmitDMA];
  8848.     }
  8849.  
  8850.     // Build interrupt list and clear interrupts.
  8851.     numInterrupts = 0;
  8852.     while ((pDCLInterrupt != nil) && (numInterrupts < 10))
  8853.     {
  8854.         pDCLInterruptList[numInterrupts] = pDCLInterrupt;
  8855.         pPrevDCLInterrupt = pDCLInterrupt->pPrevDCLInterrupt;
  8856.         pDCLInterrupt->pPrevDCLInterrupt = nil;
  8857.         numInterrupts++;
  8858.  
  8859.         pDCLInterrupt = pPrevDCLInterrupt;
  8860.     }
  8861.  
  8862.     // Run through interrupt queue.
  8863.     while (numInterrupts--)
  8864.     {
  8865.         // Get DCL command that caused interrupt.
  8866.         pDCLCommand = pDCLInterruptList[numInterrupts]->pDCLCommand;
  8867.  
  8868.         // Dispatch off of opcode.
  8869.         switch (pDCLCommand->opcode & ~kFWDCLOpFlagMask)
  8870.         {
  8871.             case kDCLCallProcOp :
  8872.                 // Call the proc.
  8873.                 pDCLCallProc = (DCLCallProcPtr) pDCLCommand;
  8874.                 FWCallDCLCallProc (pLynxIsochPortData->dclProgramID, pDCLCallProc);
  8875.                 break;
  8876.  
  8877.             case kDCLUpdateDCLListOp :
  8878.                 // Update the DCL list.
  8879.                 pDCLUpdateDCLList = (DCLUpdateDCLListPtr) pDCLCommand;
  8880.                 LynxFWIMDCLCompilerUpdateNotification (pLynxIsochPortData->dclProgramID,
  8881.                                                        pDCLUpdateDCLList->dclCommandList,
  8882.                                                        pDCLUpdateDCLList->numDCLCommands);
  8883.                 break;
  8884.  
  8885.             default :
  8886.                 break;
  8887.         }
  8888.     }
  8889. }
  8890.  
  8891.  
  8892. ////////////////////////////////////////////////////////////////////////////////
  8893. //
  8894. // LynxFWIMResetDeferredTask
  8895. //
  8896. //   This proc deals with bus resets at FireWire deferred task time.
  8897. //
  8898.  
  8899. static void    LynxFWIMResetDeferredTask(
  8900.     void                        *p1,
  8901.     void                        *p2)
  8902. {
  8903.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  8904.     AbsoluteTime                timeoutAbsolute;
  8905.     OSStatus                    status = noErr;
  8906.  
  8907. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMResetDeferredTask");
  8908.     
  8909.     // Bus reset DT no longer scheduled.
  8910.     pLynxFWIMData->busResetDTScheduled = false;
  8911.  
  8912.     // This is a temporary hack.  We want to reduce the risk of PHY jams.
  8913.     // So after a bus reset, before we process the self-IDs, wait 50ms to
  8914.     // allow another bus reset (if any) to arrive.  When this timer goes
  8915.     // off, if busResetDTScheduled has become true again, then there was
  8916.     // another bus reset.  By the time we get to the self-IDs for the first
  8917.     // reset, we'll be able to skip forward over them and avoid some PHY
  8918.     // register accesses.
  8919.     
  8920.     // If there are more resets beyond 50ms, we won't keep waiting - otherwise
  8921.     // we might hang if there were endless resets.  But hopefully we will have
  8922.     // managed to skip some of them.
  8923.  
  8924.     if (pLynxFWIMData->delayedResetTimerSet == false)
  8925.     {
  8926.         timeoutAbsolute = AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (50 * durationMillisecond));
  8927.         status = SetInterruptTimer
  8928.                     (&timeoutAbsolute,
  8929.                      LynxFWIMDelayedReset,
  8930.                      pLynxFWIMData,
  8931.                      &(pLynxFWIMData->delayedResetTimerID));
  8932.         if (status == noErr)
  8933.             pLynxFWIMData->delayedResetTimerSet = true;
  8934.             else LynxFWIMDelayedReset (p1, nil);            // Might as well proceed (should never happen)
  8935.     }
  8936. }
  8937.  
  8938.  
  8939. static OSStatus    LynxFWIMDelayedReset(
  8940.     void                        *p1,
  8941.     void                        *p2)
  8942. {
  8943.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  8944.     LynxRegistersPtr            pLynxRegs;
  8945.  
  8946.     pLynxFWIMData->delayedResetTimerSet = false;
  8947.  
  8948.     // Get base address of Lynx registers.
  8949.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  8950.  
  8951.     // Re-enable data transmission.
  8952.     LynxFWIMSetLinkControl
  8953.         (pLynxFWIMData,
  8954.          EndianSwap32Bit (pLynxRegs->linkControl) | kLynxTX_ASYNC_EN);
  8955.  
  8956.     // If there's a pending FWIM command, set its status to busReconfiguredErr.
  8957.     //zzz should we do this here, or in services?
  8958.     //zzz this probably should not be done on all types of commands.
  8959.     if (pLynxFWIMData->pPendingFWIMCommand)
  8960.     {
  8961.         if (pLynxFWIMData->pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
  8962.             pLynxFWIMData->pendingFWIMCommandStatus = busReconfiguredErr;
  8963.     }
  8964.     
  8965.     // During the period that delayedResetTimerSet was true,
  8966.     // no async packets were processed.
  8967.     // Now (another hack) process any that are waiting:
  8968.     
  8969.     LynxFWIMHandleDMAAsyncPCLInterrupt (pLynxFWIMData);
  8970.     
  8971.     return noErr;
  8972. }
  8973.  
  8974.  
  8975. ////////////////////////////////////////////////////////////////////////////////
  8976. //
  8977. // LynxFWIMMiscInterruptDeferredTask
  8978. //
  8979. //   This proc deals with miscellaneous interrupts at FireWire deferred task time.
  8980. //
  8981.  
  8982. static void    LynxFWIMMiscInterruptDeferredTask(
  8983.     void                        *p1,
  8984.     void                        *p2)
  8985. {
  8986.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1;
  8987.     UInt32                        i;
  8988.  
  8989.     // DT no longer scheduled.
  8990.     pLynxFWIMData->miscInterruptDTScheduled = false;
  8991.  
  8992.     i = pLynxFWIMData->miscInterrupt;
  8993.     pLynxFWIMData->miscInterrupt = 0;
  8994.  
  8995. #ifdef LynxFireBug
  8996.     sprintf (fireBug, "LynxFWIM:  Interrupts: %s%s%s%s%s%s%s%s%s%s",
  8997.              (i & kLynxPHY_TIME_OUT)    ? "PHY_TO "        : "",
  8998.              (i & kLynxIT_STUCK)        ? "IT_STUCK "    : "",
  8999.              (i & kLynxAT_STUCK)        ? "AT_STUCK "    : "",
  9000.              (i & kLynxHDR_ERR)            ? "CRC_ERR "    : "",
  9001.              (i & kLynxTC_ERR)            ? "TC_ERR "        : "",
  9002.              (i & kLynxCYC_LOST)        ? "CYC_LOST "    : "",
  9003.              (i & kLynxCYC_ARB_FAILED)    ? "CYC_ARB "    : "",
  9004.              (i & kLynxITF_UNDER_FLOW)    ? "ITF_UF "        : "",
  9005.              (i & kLynxATF_UNDER_FLOW)    ? "ATF_UF "        : "",
  9006.              (i & kLynxIARB_FAILED)        ? "IARB "        : "");
  9007.     //if (i) LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
  9008. #endif
  9009.  
  9010. }
  9011.  
  9012.  
  9013. ////////////////////////////////////////////////////////////////////////////////
  9014. //
  9015. // LynxFWIMAckSecondaryInterruptHandler
  9016. //
  9017. //   This proc checks the ack received for the sent transaction.  If the ack
  9018. // specifies a completed transaction, this proc will complete the transaction.
  9019. // If the ack specifies an error, this proc will retry the transaction.
  9020. //zzz need to handle response pending ack.
  9021. //zzz need locking mechanism between this routine and the timeout routine
  9022. //
  9023. // We aren't called by interrupt, we're called directly by LynxFWIMWrite()
  9024.  
  9025. static OSStatus    LynxFWIMAckSecondaryInterruptHandler(
  9026.     void                        *p1,
  9027.     void                        *p2)
  9028. {
  9029.     FWIMCommandParamsPtr        pFWIMCommandParams;
  9030.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  9031.     LynxFWIMDataPtr                pLynxFWIMData = (LynxFWIMDataPtr) p1; 
  9032.     LynxPCLPtr                    pPCL = (LynxPCLPtr) p2;
  9033.     AbsoluteTime                timeoutAbsolute;
  9034.     UInt32                        ackCode, ackType, tryAgain;
  9035.     Boolean                        commandBusy;
  9036.     OSStatus                    pendingFWIMCommandStatus,
  9037.                                 status = noErr;
  9038.  
  9039. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMAckSecondaryInterruptHandler");
  9040.  
  9041.     // Get our internal data.
  9042.     pFWIMAsynchCommandParams =
  9043.         (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
  9044.     pendingFWIMCommandStatus = pLynxFWIMData->pendingFWIMCommandStatus;
  9045.     pFWIMCommandParams = &(pFWIMAsynchCommandParams->fwimCommandParams);
  9046.  
  9047.     // Make sure pending command is a write.
  9048.     if (pFWIMCommandParams->commandType == kFWIMWrite)
  9049.     {
  9050.         if (status == noErr)
  9051.         {
  9052.             // Check if command is still busy.
  9053.             if (pendingFWIMCommandStatus == kLynxPendingFWIMCommandBusy)
  9054.             {
  9055.                 commandBusy = true;
  9056.             }
  9057.             else
  9058.             {
  9059.                 commandBusy = false;
  9060.                 status = pendingFWIMCommandStatus;
  9061.             }
  9062.     
  9063.             // Check if ack code indicates a completed transfer.  Retry if it doesn't.
  9064.             if (commandBusy)
  9065.             {
  9066.                 ackCode = (EndianSwap32Bit (pPCL->status) & kLynxAcks) >> kLynxAcksPhase;
  9067.                 ackType = ((EndianSwap32Bit (pPCL->status) & kLynxAck_Type) != 0);
  9068.                 tryAgain = 0;
  9069.                 
  9070.                 if (ackType == 0)        // Normal 1394 ack
  9071.                 {
  9072.                     if ((ackCode == kFWAckComplete) || (ackCode == kFWAckPending))
  9073.                     {
  9074.                         // This happens the majority of the time.
  9075.                         //zzz should wait for write response when ack pending
  9076.                         commandBusy = false;
  9077.                     }
  9078.                     else if (ackCode != kFWAckTypeError)
  9079.                     {
  9080.                         // This should only be AckDataError, meaning the packet we sent
  9081.                         // failed CRC at the receiver.  However, non-revA parts seem to
  9082.                         // yield ack 0 in this case.  So except for TypeError, just try
  9083.                         // again.  TypeError will probably fail again if we try again,
  9084.                         // so give up in that case.
  9085.                         tryAgain = 1;
  9086.                     }
  9087.                     else        // TypeError
  9088.                     {
  9089.                         commandBusy = false;
  9090.                         status = retryExceededErr;    //zzz do we have a better error code?
  9091.                     }
  9092.                 }
  9093.                 else                    // Some Lynx error code, not a real ack
  9094.                 {
  9095.                     if ((ackCode == 0) || (ackCode == 1))
  9096.                     {
  9097.                         // 0 indicates retry overrun (too many retries)
  9098.                         // 1 indicates Link Timeout - meaning nobody home.  Assume no Link at that Phy.
  9099.                         status = retryExceededErr;
  9100.                         commandBusy = false;
  9101.                     }
  9102.                     else if (ackCode == 2)
  9103.                     {
  9104.                         // 2 indicates FIFO underrun.  This happens sometimes.
  9105.                         // Just try again.
  9106.                         // zzz should only retry a limited number of times.
  9107.                         tryAgain = 1;
  9108.                     }
  9109.                     else    // unknown ackCode. zzz should retry some of these, needs more study
  9110.                     {
  9111.                         status = retryExceededErr;
  9112.                         commandBusy = false;
  9113.                     }
  9114.                 }
  9115.             }
  9116.                 
  9117.             if (tryAgain)
  9118.             {
  9119.                 timeoutAbsolute =
  9120.                     AddAbsoluteToAbsolute (UpTime (), DurationToAbsolute (10 * durationMillisecond));
  9121.                 status = SetInterruptTimer
  9122.                             (&timeoutAbsolute,
  9123.                              LynxFWIMWriteTimer,
  9124.                              pFWIMAsynchCommandParams,
  9125.                              &(pLynxFWIMData->requestTimeoutTimerID));
  9126.                 if (status == noErr)
  9127.                     pLynxFWIMData->requestTimeoutTimerSet = true;
  9128.  
  9129.                 if (status != noErr)
  9130.                     commandBusy = false;
  9131.             }
  9132.             
  9133.             // Complete command if it's no longer busy.
  9134.             if (!commandBusy)
  9135.             {
  9136.                 pLynxFWIMData->pPendingFWIMCommand = nil;
  9137.                 status =
  9138.                     FWIMCommandIsComplete (pFWIMCommandParams->fwimCommandID,
  9139.                                            status);
  9140.             }
  9141.         }
  9142.     }
  9143.  
  9144.     return (status);
  9145. }
  9146.  
  9147.  
  9148. ////////////////////////////////////////////////////////////////////////////////
  9149. //
  9150. // LynxFWIMProcessPacket
  9151. //
  9152. //   Dispatch packet processing based on tCode (async or isoch).
  9153. //zzz check destID???
  9154. //
  9155.  
  9156. static void LynxFWIMProcessPacket(
  9157.     LynxFWIMDataPtr                pLynxFWIMData,
  9158.     LynxPCLPtr                    pPCL,
  9159.     Ptr                            packetBuffer,
  9160.     UInt32                        packetSize)
  9161. {
  9162.     UInt32                        tCode;
  9163.     UInt32                        ackCode;
  9164.     UInt32                        pclStatus;
  9165.     UInt32                        quad0, quad1;
  9166.             
  9167.     // If we received any packet, then the GRF is not jammed.
  9168.     // This will prevent us from suspecting otherwise by mistake.
  9169.     pLynxFWIMData->lastARDMA = 0;
  9170.  
  9171.     // Get first two quads.
  9172.     quad0 = ((UInt32 *) packetBuffer)[0];
  9173.     quad1 = ((UInt32 *) packetBuffer)[1];
  9174.  
  9175.     // Compute tCode.  If length is zero or first quad is inverse of second quad,
  9176.     // set tCode to special self ID tCode.
  9177.     if ((packetSize == 0) || (quad0 == ~quad1))
  9178.         tCode = kLynxTCodeSelfID;
  9179.     else
  9180.         tCode = (quad0 & kFWPacketTCode) >> kFWPacketTCodePhase;
  9181.  
  9182.     if (tCode != kLynxTCodeSelfID)
  9183.     {
  9184.         pclStatus = EndianSwap32Bit (pPCL->status);
  9185.         ackCode = (pclStatus & kLynxAcks) >> kLynxAcksPhase;
  9186.         if ((ackCode != 1) && (ackCode != 2))
  9187.         {
  9188.             tCode = 0x0f;    // reserved
  9189.             
  9190.             //sprintf (fireBug, "LynxFWIM: Whoops, ack %ld in received packet [%08lx]",
  9191.             //         (long) ackCode, (long) pclStatus);
  9192.             //LynxFWIMFireBugMsg (pLynxFWIMData, fireBug);
  9193.         }
  9194.     }
  9195.     
  9196.     // Dispatch processing based on tCode.
  9197.     switch (tCode)
  9198.     {
  9199.         case kFWTCodeWriteQuadlet :
  9200.             LynxFWIMProcessWriteQuadletPacket
  9201.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  9202.             break;
  9203.  
  9204.         case kFWTCodeWriteBlock :
  9205.             LynxFWIMProcessWriteBlockPacket
  9206.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  9207.             break;
  9208.  
  9209.         case kFWTCodeWriteResponse :
  9210.             LynxFWIMProcessWriteResponsePacket
  9211.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  9212.             break;
  9213.  
  9214.         case kFWTCodeReadQuadlet :
  9215.             LynxFWIMProcessReadQuadletPacket
  9216.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  9217.             break;
  9218.  
  9219.         case kFWTCodeReadBlock :
  9220.             LynxFWIMProcessReadBlockPacket
  9221.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  9222.             break;
  9223.  
  9224.         case kFWTCodeReadQuadletResponse :
  9225.             LynxFWIMProcessReadQuadletResponsePacket
  9226.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  9227.             break;
  9228.  
  9229.         case kFWTCodeReadBlockResponse :
  9230.             LynxFWIMProcessReadBlockResponsePacket
  9231.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  9232.             break;
  9233.  
  9234.         case kFWTCodeLock :
  9235.             LynxFWIMProcessLockPacket
  9236.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  9237.             break;
  9238.  
  9239.         case kFWTCodeIsochronousBlock :
  9240.             LynxFWIMProcessIsochronousBlockPacket
  9241.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  9242.             break;
  9243.  
  9244.         case kFWTCodeLockResponse :
  9245.             LynxFWIMProcessLockResponsePacket
  9246.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  9247.             break;
  9248.  
  9249.         case kLynxTCodeSelfID :
  9250.             LynxFWIMProcessSelfIDPacket
  9251.                 (pLynxFWIMData, pPCL, packetBuffer, packetSize);
  9252.             break;
  9253.  
  9254.         default :
  9255.             LynxFWIMAddAsyncRxPCL (pPCL);
  9256.             break;
  9257.     }
  9258. }
  9259.  
  9260.  
  9261. ////////////////////////////////////////////////////////////////////////////////
  9262. //
  9263. // LynxFWIMProcessSelfIDPacket
  9264. //
  9265. //   This proc tries to process a selfID packet.
  9266. //zzz Should validate selfIDs by making sure the phyID is correct , there's
  9267. //zzz enough of them, etc.  Need to generate CRC. Should cancel timeout timer.
  9268. //
  9269.  
  9270. static void    LynxFWIMProcessSelfIDPacket(
  9271.     LynxFWIMDataPtr                pLynxFWIMData,
  9272.     LynxPCLPtr                    pPCL,
  9273.     Ptr                            packetBuffer,
  9274.     UInt32                        packetSize)
  9275. {
  9276.     LynxRegistersPtr            pLynxRegs;
  9277.     FWIMProcessSelfIDsParams    fwimProcessSelfIDsParams;
  9278.     UInt32                        localSelfIDQuads[2];
  9279.     UInt32                        *pSelfIDPackets = (UInt32 *) packetBuffer;
  9280.     UInt32                        localSelfID;
  9281.     UInt32                        physicalID;
  9282.     UInt32                        gapCount;                        
  9283.     UInt32                        speed;
  9284.     UInt32                        contender;
  9285.     UInt32                        portStatus;
  9286.  
  9287. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessSelfIDPacket");
  9288.  
  9289.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  9290.  
  9291.     ////////////////////////////////////////////////////////////////////////////
  9292.     //
  9293.     // Build our local selfID.
  9294.     //
  9295.  
  9296. //    FWDebugStr ((ConstStr255Param) "\pSelfID proceeding");
  9297.  
  9298.     // Get physical ID and root bit.
  9299.     physicalID = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhyPhysicalIDAddress);
  9300.     if (physicalID & kLynxPhyR)
  9301.         pLynxFWIMData->root = true;
  9302.     else
  9303.         pLynxFWIMData->root = false;
  9304.     physicalID = (physicalID & kLynxPhyPhysicalID) >> kLynxPhyPhysicalIDPhase;
  9305.     localSelfID = physicalID << kFWSelfIDPhyIDPhase;
  9306.  
  9307.     // This will have already been done by the PhyReg primary interrupt handler.
  9308.     // But do it again here just to be safe (there is a possible race condition)
  9309.     
  9310.     // Disable cycle mastering if we're not root.
  9311.     if (!pLynxFWIMData->root)
  9312.     {
  9313.         LynxFWIMSetLinkControl
  9314.             (pLynxFWIMData, EndianSwap32Bit (pLynxRegs->linkControl) & ~kLynxCYCMASTER);
  9315.     }
  9316.  
  9317.     // Get gap count.
  9318.     gapCount = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhyGCAddress);
  9319.     gapCount = (gapCount & kLynxPhyGC) >> kLynxPhyGCPhase;
  9320.     localSelfID |= gapCount << kFWSelfID0GapCntPhase;
  9321.  
  9322.     // Get speed.
  9323.     speed = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhySPDAddress);
  9324.     speed = (speed & kLynxPhySPD) >> kLynxPhySPDPhase;
  9325.     localSelfID |= speed << kFWSelfID0SPPhase;
  9326.  
  9327.     // Get contender bit.
  9328.     contender = EndianSwap32Bit (pLynxRegs->gpioData[0]);
  9329.     if (contender & 1)
  9330.         localSelfID |= kFWSelfID0C;
  9331. /*zzz should do it like this. */
  9332. #if 0
  9333.     contender = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhyCAddress);
  9334.     if (contender & kLynxPhyC)
  9335.         localSelfID |= kFWSelfID0C;
  9336. #endif
  9337.  
  9338.     // Get port status p0.
  9339.     portStatus = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhyPortStatus1Address);
  9340.     if (portStatus & kLynxPhyCon1)
  9341.     {
  9342.         if (portStatus & kLynxPhyCh1)
  9343.             localSelfID |= kFWSelfIDPortStatusChild << kFWSelfID0P0Phase;
  9344.         else
  9345.             localSelfID |= kFWSelfIDPortStatusParent << kFWSelfID0P0Phase;
  9346.     }
  9347.     else
  9348.     {
  9349.         localSelfID |= kFWSelfIDPortStatusNotConnected << kFWSelfID0P0Phase;
  9350.     }
  9351.  
  9352.     // Get port status p1.
  9353.     portStatus = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhyPortStatus2Address);
  9354.     if (portStatus & kLynxPhyCon2)
  9355.     {
  9356.         if (portStatus & kLynxPhyCh2)
  9357.             localSelfID |= kFWSelfIDPortStatusChild << kFWSelfID0P1Phase;
  9358.         else
  9359.             localSelfID |= kFWSelfIDPortStatusParent << kFWSelfID0P1Phase;
  9360.     }
  9361.     else
  9362.     {
  9363.         localSelfID |= kFWSelfIDPortStatusNotConnected << kFWSelfID0P1Phase;
  9364.     }
  9365.  
  9366.     // Get port status p2.
  9367.     portStatus = LynxFWIMReadPhyRegister (pLynxRegs, kLynxPhyPortStatus3Address);
  9368.     if (portStatus & kLynxPhyCon3)
  9369.     {
  9370.         if (portStatus & kLynxPhyCh3)
  9371.             localSelfID |= kFWSelfIDPortStatusChild << kFWSelfID0P2Phase;
  9372.         else
  9373.             localSelfID |= kFWSelfIDPortStatusParent << kFWSelfID0P2Phase;
  9374.     }
  9375.     else
  9376.     {
  9377.         localSelfID |= kFWSelfIDPortStatusNotConnected << kFWSelfID0P2Phase;
  9378.     }
  9379.  
  9380.     // Set selfID packet ID, link active, self powered and
  9381.     // provides 15W.
  9382.     //zzz 15W is just a guess.  Need to determine real number.
  9383.     localSelfID |= ((kFWSelfIDPacketID << kFWPhyPacketIDPhase) |
  9384.                     kFWSelfID0L |
  9385.                     (kFWSelfIDSelfPowered15W << kFWSelfID0PwrPhase));
  9386.  
  9387.     // Process the self IDs.
  9388.     //zzz need to get status.
  9389.     localSelfIDQuads[0] = localSelfID;
  9390.     localSelfIDQuads[1] = ~localSelfID;
  9391.     fwimProcessSelfIDsParams.fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  9392.     fwimProcessSelfIDsParams.pSelfIDList = (Ptr) pSelfIDPackets;
  9393.     fwimProcessSelfIDsParams.selfIDListSize = packetSize;
  9394.     fwimProcessSelfIDsParams.pLocalSelfID = (Ptr) localSelfIDQuads;
  9395.     fwimProcessSelfIDsParams.localSelfIDSize = 8;
  9396.     fwimProcessSelfIDsParams.processSelfIDsFlags = 0;
  9397.     FWProcessSelfIDs (&fwimProcessSelfIDsParams);
  9398.     
  9399.     pLynxFWIMData->generation = fwimProcessSelfIDsParams.generation;
  9400.     pLynxFWIMData->generationValid = true;
  9401.  
  9402.     // We used to load the nodeID register here, but this was a bad place to
  9403.     // do it.  That's now done based on PHY register receive interrupts.
  9404.     
  9405.     // Add PCL back to active list.
  9406.     LynxFWIMAddAsyncRxPCL (pPCL);
  9407. }
  9408.  
  9409.  
  9410. ////////////////////////////////////////////////////////////////////////////////
  9411. //
  9412. // LynxFWIMProcessWriteQuadletPacket
  9413. //
  9414. //   This proc processes a write quadlet packet.
  9415. //
  9416.  
  9417. static void    LynxFWIMProcessWriteQuadletPacket(
  9418.     LynxFWIMDataPtr                pLynxFWIMData,
  9419.     LynxPCLPtr                    pPCL,
  9420.     Ptr                            packetBuffer,
  9421.     UInt32                        packetSize)
  9422. {
  9423.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  9424.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  9425.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  9426.     UInt32                        pclStatus;
  9427.     UInt32                        transactionStatus;
  9428.  
  9429. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessWriteQuadletPacket");
  9430.  
  9431.     // Get PCL data.
  9432.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  9433.  
  9434.     // Fill in processing params.
  9435.     pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
  9436.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  9437.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  9438.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  9439.         LynxFWIMProcessWriteQuadletRequestCompletionProc;
  9440.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
  9441.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  9442.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[3]);
  9443.     pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
  9444.     BlockCopy (packetBuffer,
  9445.                &(pFWIMProcessAsynchParams->destinationID),
  9446.                3 * sizeof (UInt32));
  9447.     pFWIMProcessAsynchParams->length = 4;
  9448.     pFWIMProcessAsynchParams->extendedTCode = 0;
  9449.  
  9450.     pclStatus = EndianSwap32Bit (pPCL->status);
  9451.     transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
  9452.                         kFWTransactionStatusAckCodePhase;
  9453.     transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
  9454.                          kFWTransactionStatusSpeedPhase;
  9455.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  9456.  
  9457.     // Process the write request.
  9458.     FWProcessWriteRequest (pFWIMProcessAsynchParams);
  9459. }
  9460.  
  9461.  
  9462. ////////////////////////////////////////////////////////////////////////////////
  9463. //
  9464. // LynxFWIMProcessWriteQuadletRequestCompletionProc
  9465. //
  9466. //   This proc will be called upon completion of write request processing.
  9467. //
  9468.  
  9469. static void    LynxFWIMProcessWriteQuadletRequestCompletionProc(
  9470.     FWIMProcessParamsPtr        pFWIMProcessParams)
  9471. {
  9472.     LynxPCLPtr                    pPCL;
  9473.  
  9474.     // Get PCL pointer.
  9475.     pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
  9476.  
  9477.     // Add PCL back to active list.
  9478.     LynxFWIMAddAsyncRxPCL (pPCL);
  9479. }
  9480.  
  9481.  
  9482. ////////////////////////////////////////////////////////////////////////////////
  9483. //
  9484. // LynxFWIMProcessWriteBlockPacket
  9485. //
  9486. //   This proc processes a write block packet.
  9487. //
  9488.  
  9489. static void    LynxFWIMProcessWriteBlockPacket(
  9490.     LynxFWIMDataPtr                pLynxFWIMData,
  9491.     LynxPCLPtr                    pPCL,
  9492.     Ptr                            packetBuffer,
  9493.     UInt32                        packetSize)
  9494. {
  9495.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  9496.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  9497.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  9498.     UInt32                        pclStatus;
  9499.     UInt32                        transactionStatus;
  9500.  
  9501. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessWriteBlockPacket");
  9502.         
  9503.     // Get PCL data.
  9504.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  9505.  
  9506.     // Fill in processing params.
  9507.     pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
  9508.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  9509.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  9510.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  9511.         LynxFWIMProcessWriteBlockRequestCompletionProc;
  9512.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
  9513.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  9514.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);
  9515.     pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
  9516.     BlockCopy (packetBuffer,
  9517.                &(pFWIMProcessAsynchParams->destinationID),
  9518.                4 * sizeof (UInt32));
  9519.  
  9520.     pclStatus = EndianSwap32Bit (pPCL->status);
  9521.     transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
  9522.                         kFWTransactionStatusAckCodePhase;
  9523.     transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
  9524.                          kFWTransactionStatusSpeedPhase;
  9525.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  9526.  
  9527.     // Process the write request.
  9528.     FWProcessWriteRequest (pFWIMProcessAsynchParams);
  9529. }
  9530.  
  9531.  
  9532. ////////////////////////////////////////////////////////////////////////////////
  9533. //
  9534. // LynxFWIMProcessWriteBlockRequestCompletionProc
  9535. //
  9536. //   This proc will be called upon completion of write request processing.
  9537. //
  9538.  
  9539. static void    LynxFWIMProcessWriteBlockRequestCompletionProc(
  9540.     FWIMProcessParamsPtr        pFWIMProcessParams)
  9541. {
  9542.     LynxPCLPtr                    pPCL;
  9543.  
  9544.     // Get PCL pointer.
  9545.     pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
  9546.  
  9547.     // Add PCL back to active list.
  9548.     LynxFWIMAddAsyncRxPCL (pPCL);
  9549. }
  9550.  
  9551.  
  9552. ////////////////////////////////////////////////////////////////////////////////
  9553. //
  9554. // LynxFWIMProcessWriteResponsePacket
  9555. //
  9556. //   This proc processes a write quadlet response packet.
  9557. //zzz Verify destinationID, and sourceID.
  9558. //
  9559. // NYI - never tested (never happens? same in TIFWIM)
  9560.  
  9561. static void    LynxFWIMProcessWriteResponsePacket(
  9562.     LynxFWIMDataPtr                pLynxFWIMData,
  9563.     LynxPCLPtr                    pPCL,
  9564.     Ptr                            packetBuffer,
  9565.     UInt32                        packetSize)
  9566. {
  9567. #if 0
  9568.     LynxRegistersPtr            pLynxRegs;
  9569.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  9570.     UInt32                        *pPacket;
  9571.     UInt32                        commandType;
  9572.     UInt32                        tLabel;
  9573.     AbsoluteTime                timeRemaining;
  9574.     OSStatus                    status = noErr;
  9575. #endif
  9576.  
  9577. //    FWDebugStr ((ConstStr255Param) "\pNYI LynxFWIMProcessWriteResponsePacket");
  9578. #if 0
  9579.     // Get pointer to link registers.
  9580.     pLinkRegs = (TILinkRegistersPtr) (pLynxFWIMData->regBaseAddress +
  9581.                                       kTILinkRegistersOffset);
  9582.  
  9583.     // Read in rest of packet.
  9584.     pPacket = (UInt32 *) packetBuffer;
  9585.     pPacket++;
  9586.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  9587.     SynchronizeIO ();
  9588.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  9589.     SynchronizeIO ();
  9590.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  9591.     SynchronizeIO ();
  9592.     *pPacket++ = EndianSwap32Bit (pLinkRegs->grfData);
  9593.     SynchronizeIO ();
  9594.  
  9595.     pPacket = (UInt32 *) packetBuffer;
  9596.  
  9597.     // Get the pending FWIM command if there is one.
  9598.     pFWIMAsynchCommandParams =
  9599.         (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
  9600.  
  9601.     // We must have a pending write command and a matching transaction label.
  9602.     if (pFWIMAsynchCommandParams != nil)
  9603.     {
  9604.         // Get pending command type and transaction label for this packet.
  9605.         commandType =
  9606.             pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  9607.         tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
  9608.  
  9609.         if ((commandType == kFWIMWrite) &&
  9610.             (tLabel == pLynxFWIMData->transactionLabel) &&
  9611.             ((pLynxFWIMData->tCode == kFWTCodeWriteQuadlet) ||
  9612.              (pLynxFWIMData->tCode == kFWTCodeWriteBlock)))
  9613.         {
  9614.             // Try to cancel timeout timer.
  9615.             status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
  9616.                                   &timeRemaining);
  9617.  
  9618.             // Complete command if we didn't time out.
  9619.             if (status == noErr)
  9620.             {
  9621.                 // Finish up command.
  9622.                 pLynxFWIMData->pPendingFWIMCommand = nil;
  9623.                 status = FWIMCommandIsComplete
  9624.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  9625.                      noErr);
  9626.             }
  9627.         }
  9628.     }
  9629. #endif
  9630.  
  9631.     // Add PCL back to active list.
  9632.     LynxFWIMAddAsyncRxPCL (pPCL);
  9633. }
  9634.  
  9635.  
  9636. ////////////////////////////////////////////////////////////////////////////////
  9637. //
  9638. // LynxFWIMProcessReadQuadletPacket
  9639. //
  9640. //   This proc processes a read quadlet packet.
  9641. //
  9642.  
  9643. static void    LynxFWIMProcessReadQuadletPacket(
  9644.     LynxFWIMDataPtr                pLynxFWIMData,
  9645.     LynxPCLPtr                    pPCL,
  9646.     Ptr                            packetBuffer,
  9647.     UInt32                        packetSize)
  9648. {
  9649.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  9650.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  9651.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  9652.     UInt32                        pclStatus;
  9653.     UInt32                        transactionStatus;
  9654.  
  9655.     // Get PCL data.
  9656.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  9657.  
  9658.     // Fill in processing params.
  9659.     pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
  9660.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  9661.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  9662.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  9663.         LynxFWIMProcessReadQuadletRequestCompletionProc;
  9664.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
  9665.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  9666.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[3]);//zzz should probably be nil.
  9667.     pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
  9668.     BlockCopy (packetBuffer,
  9669.                &(pFWIMProcessAsynchParams->destinationID),
  9670.                3 * sizeof (UInt32));
  9671.     pFWIMProcessAsynchParams->length = 4;
  9672.     pFWIMProcessAsynchParams->extendedTCode = 0;
  9673.     pclStatus = EndianSwap32Bit (pPCL->status);
  9674.  
  9675.     pclStatus = EndianSwap32Bit (pPCL->status);
  9676.     transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
  9677.                         kFWTransactionStatusAckCodePhase;
  9678.     transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
  9679.                          kFWTransactionStatusSpeedPhase;
  9680.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  9681.  
  9682.     // Process the read request.
  9683.     FWProcessReadRequest (pFWIMProcessAsynchParams);
  9684. }
  9685.  
  9686.  
  9687. ////////////////////////////////////////////////////////////////////////////////
  9688. //
  9689. // LynxFWIMProcessReadQuadletRequestCompletionProc
  9690. //
  9691. //   This proc will be called upon completion of read request processing.
  9692. //
  9693.  
  9694. static void    LynxFWIMProcessReadQuadletRequestCompletionProc(
  9695.     FWIMProcessParamsPtr        pFWIMProcessParams)
  9696. {
  9697.     LynxPCLPtr                    pPCL;
  9698.  
  9699.     // Get PCL pointer.
  9700.     pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
  9701.  
  9702.     // Add PCL back to active list.
  9703.     LynxFWIMAddAsyncRxPCL (pPCL);
  9704. }
  9705.  
  9706.  
  9707. ////////////////////////////////////////////////////////////////////////////////
  9708. //
  9709. // LynxFWIMProcessReadBlockPacket
  9710. //
  9711. //   This proc processes a read block packet.
  9712. //
  9713.  
  9714. static void    LynxFWIMProcessReadBlockPacket(
  9715.     LynxFWIMDataPtr                pLynxFWIMData,
  9716.     LynxPCLPtr                    pPCL,
  9717.     Ptr                            packetBuffer,
  9718.     UInt32                        packetSize)
  9719. {
  9720.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  9721.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  9722.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  9723.     UInt32                        pclStatus;
  9724.     UInt32                        transactionStatus;
  9725.  
  9726.     // Get PCL data.
  9727.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  9728.  
  9729.     // Fill in processing params.
  9730.     pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
  9731.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  9732.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  9733.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  9734.         LynxFWIMProcessReadBlockRequestCompletionProc;
  9735.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
  9736.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  9737.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);//zzz should probably be nil
  9738.     pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
  9739.     BlockCopy (packetBuffer,
  9740.                &(pFWIMProcessAsynchParams->destinationID),
  9741.                4 * sizeof (UInt32));
  9742.  
  9743.     pclStatus = EndianSwap32Bit (pPCL->status);
  9744.     transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
  9745.                         kFWTransactionStatusAckCodePhase;
  9746.     transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
  9747.                          kFWTransactionStatusSpeedPhase;
  9748.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  9749.  
  9750.     // Process the read request.    
  9751.     FWProcessReadRequest (pFWIMProcessAsynchParams);
  9752. }
  9753.  
  9754.  
  9755. ////////////////////////////////////////////////////////////////////////////////
  9756. //
  9757. // LynxFWIMProcessReadBlockRequestCompletionProc
  9758. //
  9759. //   This proc will be called upon completion of read request processing.
  9760. //
  9761.  
  9762. static void    LynxFWIMProcessReadBlockRequestCompletionProc(
  9763.     FWIMProcessParamsPtr        pFWIMProcessParams)
  9764. {
  9765.     LynxPCLPtr                    pPCL;
  9766.  
  9767.     // Get PCL pointer.
  9768.     pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
  9769.  
  9770.     // Add PCL back to active list.
  9771.     LynxFWIMAddAsyncRxPCL (pPCL);
  9772. }
  9773.  
  9774.  
  9775. ////////////////////////////////////////////////////////////////////////////////
  9776. //
  9777. // LynxFWIMProcessReadQuadletResponsePacket
  9778. //
  9779. //   This proc processes a read quadlet response packet.
  9780. //zzz Verify destinationID, and sourceID.
  9781. //
  9782.  
  9783. static void    LynxFWIMProcessReadQuadletResponsePacket(
  9784.     LynxFWIMDataPtr                pLynxFWIMData,
  9785.     LynxPCLPtr                    pPCL,
  9786.     Ptr                            packetBuffer,
  9787.     UInt32                        packetSize)
  9788. {
  9789.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  9790.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  9791.     UInt32                        commandType;
  9792.     UInt32                        tLabel;
  9793.     UInt32                        rCode;
  9794.     UInt32                        *commandBuffer;
  9795.     AbsoluteTime                timeRemaining;
  9796.     OSStatus                    status = noErr,
  9797.                                 responseStatus = noErr;
  9798.  
  9799. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessReadQuadletResponsePacket");
  9800.  
  9801.     // Get the pending FWIM command if there is one.
  9802.     pFWIMAsynchCommandParams =
  9803.         (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
  9804.  
  9805.     // We must have a pending read command and a matching transaction label.
  9806.     if (pFWIMAsynchCommandParams != nil)
  9807.     {
  9808.         // Get pending command type, transaction label, and response code for this packet.
  9809.         commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  9810.         tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
  9811.         rCode = (pPacket[1] & kFWAsynchRCode) >> kFWAsynchRCodePhase;
  9812.  
  9813.         if ((commandType == kFWIMRead) &&
  9814.             (tLabel == pLynxFWIMData->transactionLabel) &&
  9815.             (pLynxFWIMData->tCode == kFWTCodeReadQuadlet))
  9816.         {
  9817.             // Try to cancel timeout timer.
  9818.             status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
  9819.                                   &timeRemaining);
  9820.  
  9821.             // Complete command if we didn't time out.
  9822.             if (status == noErr)
  9823.             {
  9824.                 // Fill in command buffer.
  9825.                 if (rCode == kFWResponseComplete)
  9826.                 {
  9827.                     commandBuffer = (UInt32 *) pFWIMAsynchCommandParams->buffer;
  9828.                     *commandBuffer = pPacket[3];
  9829.                 }
  9830.                 else
  9831.                 {
  9832.                     responseStatus = accessErr;//zzz not always the best
  9833.                 }
  9834.     
  9835.                 // Finish up command.
  9836.                 pLynxFWIMData->pPendingFWIMCommand = nil;
  9837.                 status = FWIMCommandIsComplete
  9838.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  9839.                      responseStatus);
  9840.             }
  9841.         }
  9842.     }
  9843.  
  9844.     // Add PCL back to active list.
  9845.     LynxFWIMAddAsyncRxPCL (pPCL);
  9846. }
  9847.  
  9848.  
  9849. ////////////////////////////////////////////////////////////////////////////////
  9850. //
  9851. // LynxFWIMProcessReadBlockResponsePacket
  9852. //
  9853. //   This proc processes a read block response packet.
  9854. //zzz Verify destinationID, and sourceID.
  9855. //zzz Must check extended tCode.
  9856. //zzz Must return actual number of bytes transferred.
  9857. //
  9858. // NYI - never tested with Lynx
  9859.  
  9860. static void    LynxFWIMProcessReadBlockResponsePacket(
  9861.     LynxFWIMDataPtr                pLynxFWIMData,
  9862.     LynxPCLPtr                    pPCL,
  9863.     Ptr                            packetBuffer,
  9864.     UInt32                        packetSize)
  9865. {
  9866.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  9867.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  9868.     UInt32                        commandType;
  9869.     UInt32                        tLabel;
  9870.     UInt32                        rCode;
  9871.     UInt32                        dataLength;
  9872.     AbsoluteTime                timeRemaining;
  9873.     OSStatus                    status = noErr,
  9874.                                 responseStatus = noErr;
  9875.  
  9876. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessReadBlockResponsePacket");
  9877.  
  9878.     dataLength = (((UInt32 *) packetBuffer)[3] & kFWAsynchDataLength) >>
  9879.                   kFWAsynchDataLengthPhase;
  9880.     
  9881.     // Get the pending FWIM command if there is one.
  9882.     pFWIMAsynchCommandParams =
  9883.         (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
  9884.  
  9885.     // We must have a pending read command and a matching transaction label.
  9886.     if (pFWIMAsynchCommandParams != nil)
  9887.     {
  9888.         // Get pending command type, transaction label, and response code for this packet.
  9889.         commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  9890.         tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
  9891.         rCode = (pPacket[1] & kFWAsynchRCode) >> kFWAsynchRCodePhase;
  9892.  
  9893.         if ((commandType == kFWIMRead) &&
  9894.             (tLabel == pLynxFWIMData->transactionLabel) &&
  9895.             (pLynxFWIMData->tCode == kFWTCodeReadBlock))
  9896.         {
  9897.             // Try to cancel timeout timer.
  9898.             status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
  9899.                                   &timeRemaining);
  9900.  
  9901.             // Complete command if we didn't time out.
  9902.             if (status == noErr)
  9903.             {
  9904.                 // Fill in command buffer.
  9905.                 if (rCode == kFWResponseComplete)
  9906.                 {
  9907.                     if (dataLength > pFWIMAsynchCommandParams->length)
  9908.                         dataLength = pFWIMAsynchCommandParams->length;
  9909.                     BlockCopy (&(pPacket[4]),
  9910.                                pFWIMAsynchCommandParams->buffer,
  9911.                                dataLength);
  9912.                 }
  9913.                 else
  9914.                 {
  9915.                     responseStatus = accessErr;//zzz not always the best
  9916.                 }
  9917.  
  9918.                 // Finish up command.
  9919.                 pLynxFWIMData->pPendingFWIMCommand = nil;
  9920.                 status = FWIMCommandIsComplete
  9921.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  9922.                      responseStatus);
  9923.             }
  9924.         }
  9925.     }
  9926.  
  9927.     // Add PCL back to active list.
  9928.     LynxFWIMAddAsyncRxPCL (pPCL);
  9929. }
  9930.  
  9931.  
  9932. ////////////////////////////////////////////////////////////////////////////////
  9933. //
  9934. // LynxFWIMProcessLockPacket
  9935. //
  9936. //   This proc processes a lock packet.
  9937. //
  9938.  
  9939. static void    LynxFWIMProcessLockPacket(
  9940.     LynxFWIMDataPtr                pLynxFWIMData,
  9941.     LynxPCLPtr                    pPCL,
  9942.     Ptr                            packetBuffer,
  9943.     UInt32                        packetSize)
  9944. {
  9945.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  9946.     LynxAsyncRxPCLDataPtr        pLynxAsyncRxPCLData;
  9947.     FWIMProcessAsynchParamsPtr    pFWIMProcessAsynchParams;
  9948.     UInt32                        pclStatus;
  9949.     UInt32                        transactionStatus;
  9950.  
  9951.     // Get PCL data.
  9952.     pLynxAsyncRxPCLData = (LynxAsyncRxPCLDataPtr) pPCL->refCon;
  9953.  
  9954.     // Fill in processing params.
  9955.     pFWIMProcessAsynchParams = &(pLynxAsyncRxPCLData->fwimProcessAsynchParams);
  9956.     pFWIMProcessAsynchParams->fwimProcessParams.fwimID = pLynxFWIMData->fwimID;
  9957.     pFWIMProcessAsynchParams->fwimProcessParams.processFlags = 0;
  9958.     pFWIMProcessAsynchParams->fwimProcessParams.completionProc =
  9959.         LynxFWIMProcessLockRequestCompletionProc;
  9960.     pFWIMProcessAsynchParams->fwimProcessParams.completionProcData = (UInt32) pPCL;
  9961.     pFWIMProcessAsynchParams->timeStamp = UpTime ();//zzz need more accurate time stamp
  9962.     pFWIMProcessAsynchParams->receiveBuffer = (Ptr) &(pPacket[4]);//zzz receive and transmit buffers should be different
  9963.     pFWIMProcessAsynchParams->generation = pLynxFWIMData->generation;//zzz needs to be more accurate.
  9964.     BlockCopy (packetBuffer,
  9965.                &(pFWIMProcessAsynchParams->destinationID),
  9966.                4 * sizeof (UInt32));
  9967.  
  9968.     pclStatus = EndianSwap32Bit (pPCL->status);
  9969.     transactionStatus = ((pclStatus & kLynxAcks) >> kLynxAcksPhase) <<
  9970.                         kFWTransactionStatusAckCodePhase;
  9971.     transactionStatus |= ((pclStatus & kLynxRcv_Speed) >> kLynxRcv_SpeedPhase) <<
  9972.                          kFWTransactionStatusSpeedPhase;
  9973.     pFWIMProcessAsynchParams->transactionStatus = transactionStatus;
  9974.  
  9975.     // Process the lock request.
  9976.     FWProcessLockRequest (pFWIMProcessAsynchParams);
  9977. }
  9978.  
  9979.  
  9980. ////////////////////////////////////////////////////////////////////////////////
  9981. //
  9982. // LynxFWIMProcessLockRequestCompletionProc
  9983. //
  9984. //   This proc will be called upon completion of lock request processing.
  9985. //
  9986.  
  9987. static void    LynxFWIMProcessLockRequestCompletionProc(
  9988.     FWIMProcessParamsPtr        pFWIMProcessParams)
  9989. {
  9990.     LynxPCLPtr                    pPCL;
  9991.  
  9992.     // Get PCL pointer.
  9993.     pPCL = (LynxPCLPtr) pFWIMProcessParams->completionProcData;
  9994.  
  9995.     // Add PCL back to active list.
  9996.     LynxFWIMAddAsyncRxPCL (pPCL);
  9997. }
  9998.  
  9999.  
  10000. ////////////////////////////////////////////////////////////////////////////////
  10001. //
  10002. // LynxFWIMProcessIsochronousBlockPacket
  10003. //
  10004. //   This proc processes an isochronous block packet.
  10005. //zzz Verify destinationID, and sourceID.
  10006. //zzz need to determine which port this packet is for.
  10007. //zzz should break this proc up.
  10008. //zzz data length not accurate if not a multiple of 4.
  10009. //zzz should implement all the synch stuff.
  10010. //
  10011. //   Important:  We don't service additional packets while the channel handler runs.
  10012. //zzz
  10013. //zzz this code is obsolete and needs to be updated before it will work
  10014. //zzz
  10015.  
  10016. static void    LynxFWIMProcessIsochronousBlockPacket(
  10017.     LynxFWIMDataPtr                pLynxFWIMData,
  10018.     LynxPCLPtr                    pPCL,
  10019.     Ptr                            packetBuffer,
  10020.     UInt32                        packetSize)
  10021. {
  10022. /*zzz*/
  10023. #if 0
  10024. /*zzz*/
  10025.     FWIMAllocateIsochPortParamsPtr
  10026.                                 pFWIMAllocateIsochPortParams;
  10027.     LynxIsochPortDataPtr        pLynxIsochPortData;
  10028.     DCLCommandPtr                pDCLCommand;
  10029.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  10030.     UInt32                        channelNum,
  10031.                                 commandChannelNum;
  10032.     UInt32                        dataLength;
  10033.     Boolean                        disablePort = false;
  10034.  
  10035. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessIsochronousBlockPacket");
  10036.  
  10037.     // Get the pending FWIM command if there is one.
  10038.     pFWIMAllocateIsochPortParams = (FWIMAllocateIsochPortParamsPtr)
  10039.         &(pLynxFWIMData->fwimAllocateIsochPortParams);
  10040.  
  10041.     // We must have an active isochronous command and a matching channel number.
  10042.     //zzz how do we tell it's active.
  10043.     if (pFWIMAllocateIsochPortParams->fwimCommandParams.fwimCommandID !=
  10044.         kInvalidFWIMCommandID)
  10045.     {
  10046.         // Get isoch port data.
  10047.         pLynxIsochPortData = (LynxIsochPortDataPtr)
  10048.             pFWIMAllocateIsochPortParams->fwimIsochPortCommandParams.fwimIsochPortData;
  10049.  
  10050.         // Get pending command type and channel number for this packet.
  10051.         commandChannelNum = pFWIMAllocateIsochPortParams->channelNum;
  10052.         channelNum = (pPacket[0] & kFWIsochChanNum) >> kFWIsochChanNumPhase;
  10053.  
  10054.         if (channelNum == commandChannelNum)
  10055.         {
  10056.             // Get the DCL command.
  10057.             pDCLCommand = pLynxFWIMData->pCurrentDCLCommand;
  10058.  
  10059.             // Compute data length for this buffer.
  10060.             dataLength = (((UInt32 *) pPacket)[0] & kFWIsochDataLength) >>
  10061.                          kFWIsochDataLengthPhase;
  10062.             if (dataLength & 0x03)
  10063.                 dataLength = (dataLength & 0xFFFFFFFC) + 4;        // round up to quadwords
  10064.  
  10065.             // Fill the isoch buffers.
  10066.             if (pDCLCommand != nil)
  10067.             {
  10068.                 LynxFWIMRunDCLProgram
  10069.                     (pLynxIsochPortData, (Ptr) pPacket, dataLength, &pDCLCommand);
  10070.                 pLynxFWIMData->pCurrentDCLCommand = pDCLCommand;
  10071.             }
  10072.  
  10073.             // If we've run out of buffers, disable port.
  10074.             if (pDCLCommand == nil)
  10075.                 disablePort = true;
  10076.         }
  10077.     }
  10078.  
  10079.     // Disable the port if we need to.
  10080.     if (disablePort)
  10081.     {
  10082.     
  10083. // NYI - If we reprogram the DMA comparators, we won't get any more Isoch.
  10084. // Maybe that would be a good idea.
  10085.  
  10086.     }
  10087.  
  10088. /*zzz*/
  10089. #endif
  10090. /*zzz*/
  10091.  
  10092.     // Add PCL back to active list.
  10093.     LynxFWIMAddAsyncRxPCL (pPCL);
  10094. }
  10095.  
  10096.  
  10097. ////////////////////////////////////////////////////////////////////////////////
  10098. //
  10099. // LynxFWIMProcessLockResponsePacket
  10100. //
  10101. //   This proc processes a lock response packet.
  10102. //zzz Verify destinationID, and sourceID.
  10103. //zzz Must check extended tCode.
  10104. //
  10105. // (IRM sends these)
  10106.  
  10107. static void    LynxFWIMProcessLockResponsePacket(
  10108.     LynxFWIMDataPtr                pLynxFWIMData,
  10109.     LynxPCLPtr                    pPCL,
  10110.     Ptr                            packetBuffer,
  10111.     UInt32                        packetSize)
  10112. {
  10113.     FWIMAsynchCommandParamsPtr    pFWIMAsynchCommandParams;
  10114.     UInt32                        *pPacket = (UInt32 *) packetBuffer;
  10115.     UInt32                        commandType;
  10116.     UInt32                        tLabel;
  10117.     UInt32                        rCode;
  10118.     UInt32                        dataLength;
  10119.     AbsoluteTime                timeRemaining;
  10120.     OSStatus                    status = noErr,
  10121.                                 responseStatus = noErr;
  10122.  
  10123. //    FWDebugStr ((ConstStr255Param) "\pLynxFWIMProcessLockResponsePacket");
  10124.  
  10125.     dataLength = (pPacket[3] & kFWAsynchDataLength) >> kFWAsynchDataLengthPhase;
  10126.     if (dataLength & 0x03)
  10127.         dataLength = (dataLength & 0xFFFFFFFC) + 4;
  10128.  
  10129.     // Get the pending FWIM command if there is one.
  10130.     pFWIMAsynchCommandParams =
  10131.         (FWIMAsynchCommandParamsPtr) pLynxFWIMData->pPendingFWIMCommand;
  10132.  
  10133.     // We must have a pending lock command and a matching transaction label.
  10134.     if (pFWIMAsynchCommandParams != nil)
  10135.     {
  10136.         // Get pending command type, transaction label, and response code for this packet.
  10137.         commandType = pFWIMAsynchCommandParams->fwimCommandParams.commandType;
  10138.         tLabel = (pPacket[0] & kFWAsynchTLabel) >> kFWAsynchTLabelPhase;
  10139.         rCode = (pPacket[1] & kFWAsynchRCode) >> kFWAsynchRCodePhase;
  10140.  
  10141.         if ((commandType == kFWIMLock) &&
  10142.             (tLabel == pLynxFWIMData->transactionLabel) &&
  10143.             (pLynxFWIMData->tCode == kFWTCodeLock))
  10144.         {
  10145.             // Try to cancel timeout timer.
  10146.             status = CancelTimer (pLynxFWIMData->requestTimeoutTimerID,
  10147.                                   &timeRemaining);
  10148.  
  10149.             // Complete command if we didn't time out.
  10150.             if (status == noErr)
  10151.             {
  10152.                 // Fill in command buffer.
  10153.                 if (rCode == kFWResponseComplete)
  10154.                 {
  10155.                     if (dataLength > pFWIMAsynchCommandParams->length)
  10156.                         dataLength = pFWIMAsynchCommandParams->length;
  10157.                     BlockCopy (&(pPacket[4]),
  10158.                                pFWIMAsynchCommandParams->buffer,
  10159.                                dataLength);
  10160.                 }
  10161.                 else
  10162.                 {
  10163.                     responseStatus = accessErr;//zzz not always the best
  10164.                 }
  10165.     
  10166.                 // Finish up command.
  10167.                 pLynxFWIMData->pPendingFWIMCommand = nil;
  10168.                 status = FWIMCommandIsComplete
  10169.                     (pFWIMAsynchCommandParams->fwimCommandParams.fwimCommandID,
  10170.                      responseStatus);
  10171.             }
  10172.         }
  10173.     }
  10174.  
  10175.     // Add PCL back to active list.
  10176.     LynxFWIMAddAsyncRxPCL (pPCL);
  10177. }
  10178.  
  10179.  
  10180. ////////////////////////////////////////////////////////////////////////////////
  10181. //
  10182. // LynxFWIMSetupFIFOs
  10183. //
  10184. //   This proc sets up the FIFO sizes and thresholds.
  10185. //zzz this does have safety problems if there's stuff in the FIFOs.
  10186. //
  10187.  
  10188. static void    LynxFWIMSetupFIFOs(
  10189.     LynxFWIMDataPtr                pLynxFWIMData)
  10190. {
  10191.     LynxRegistersPtr            pLynxRegs;
  10192.  
  10193.     // Get base address for Lynx registers.
  10194.     pLynxRegs = pLynxFWIMData->pLynxRegisters;
  10195.  
  10196.     // Set up FIFOs depending on isochronous transmit mode.
  10197.     if (pLynxFWIMData->isochTransmitMode)
  10198.     {
  10199.         // Flush the FIFOs.
  10200.         pLynxRegs->fifoControlEnableAndTest =
  10201.             EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH);
  10202.         SynchronizeIO ();
  10203.         
  10204.         // Raise threshold so stuff won't accidentally go out.
  10205.         pLynxRegs->fifoTransmitThreshold = EndianSwapImm32Bit (0x0000FFFF);
  10206.         SynchronizeIO ();
  10207.         
  10208.         // Set the FIFO sizes.
  10209.         pLynxRegs->fifoSize =
  10210.             EndianSwapImm32Bit ( (kIsochTransmitModeITFSize << kLynxITF_FIFOSZPhase) |
  10211.                                  (kIsochTransmitModeATFSize << kLynxATF_FIFOSZPhase) |
  10212.                                  (kIsochTransmitModeGRFSize << kLynxGRF_FIFOSZPhase) );
  10213.         SynchronizeIO ();
  10214.  
  10215.         // Set the FIFO thresholds.
  10216.         pLynxRegs->fifoTransmitThreshold =
  10217.             EndianSwapImm32Bit ( (kIsochTransmitModeITFThreshold << kLynxITF_TRSHLDPhase) |
  10218.                                  (kIsochTransmitModeATFThreshold << kLynxATF_TRSHLDPhase) );
  10219.  
  10220.         // Flush the FIFOs just to be sure.
  10221.         pLynxRegs->fifoControlEnableAndTest =
  10222.             EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH);
  10223.         SynchronizeIO ();
  10224.     }
  10225.     else
  10226.     {
  10227.         // Flush the FIFOs.
  10228.         pLynxRegs->fifoControlEnableAndTest =
  10229.             EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH);
  10230.         SynchronizeIO ();
  10231.  
  10232.         // Raise threshold so stuff won't accidentally go out.
  10233.         pLynxRegs->fifoTransmitThreshold = EndianSwapImm32Bit (0x0000FFFF);
  10234.         SynchronizeIO ();
  10235.         
  10236.         // Set the FIFO sizes.
  10237.         pLynxRegs->fifoSize =
  10238.             EndianSwapImm32Bit ( (kDefaultITFSize << kLynxITF_FIFOSZPhase) |
  10239.                                  (kDefaultATFSize << kLynxATF_FIFOSZPhase) |
  10240.                                  (kDefaultGRFSize << kLynxGRF_FIFOSZPhase) );
  10241.         SynchronizeIO ();
  10242.  
  10243.         // Set the FIFO thresholds.
  10244.         pLynxRegs->fifoTransmitThreshold =
  10245.             EndianSwapImm32Bit ( (kDefaultITFThreshold << kLynxITF_TRSHLDPhase) |
  10246.                                  (kDefaultATFThreshold << kLynxATF_TRSHLDPhase) );
  10247.  
  10248.         // Flush the FIFOs just to be sure.
  10249.         pLynxRegs->fifoControlEnableAndTest =
  10250.             EndianSwapImm32Bit (kLynxGRF_FLUSH | kLynxITF_FLUSH | kLynxATF_FLUSH);
  10251.         SynchronizeIO ();
  10252.     }
  10253. }
  10254.  
  10255.  
  10256. static void LynxFWIMFireBugMsg (
  10257.     LynxFWIMDataPtr                pLynxFWIMData,
  10258.     char                         *msg)
  10259. {
  10260.     UInt32                        sourceID;
  10261.  
  10262.     sourceID = EndianSwap32Bit (pLynxFWIMData->pLynxRegisters->busNumberNodeNumber);
  10263.     
  10264.     LynxFWIMWriteATF (pLynxFWIMData, kLynxDMA_XMT, kFWSpeed100MBit, 4,
  10265.                       0x42420010, sourceID, 0x0, (strlen (msg) + 1) << 16,
  10266.                       strlen (msg) + 1, (UInt32 *) msg);
  10267. }
  10268.  
  10269.  
  10270. /////////////////////////
  10271. //  End of LynxFWIM.c  //
  10272. /////////////////////////